Routing issue on Nested Resource Custom Update Method - ruby

Im Building out a Rails app in Rails 4 Ruby 2
Background:
I have built a custom Method in a controller that allows me to update a table by button click.
I had some help building out the button, however it only updates the first id, in the nested element.
I am looking for said button when pushed to target only the line item its sitting in.
The button/link:
<%= link_to "Remove Unit", [#call, responding], class: 'btn btn-danger btn-sm', method: :delete, confirm: "Are you sure you want to remove this unit?" %><%= link_to "Responding", unit_responding_update_call_responding_path(call_id: #call.id, id: #respondings.first.id), method: :patch %>
this button is displayed with in a <%= #respondings.each do |responding| %> and should populate with each line item that is added, so that it can update that record when pushed.
the controller action is:
def unit_responding_update
#call = Call.find(params[:call_id])
#responding = Responding.find(params[:id])
#responding.responding_tme = DateTime.now
#responding.responding = "true"
#responding.on_scene = "false"
#responding.clear = "false"
#responding.save!
respond_to do |format|
if #responding.save
format.html { redirect_to #call, notice: "Responding time successfully updated." }
else
format.html { render action: 'edit' }
end
end
end
Routes.rb is:
resources :calls do
resources :respondings, except: [:index], controller: 'calls/respondings' do
member do
patch :unit_responding_update
end
end
resources :pings, except: [:index], controller: 'calls/pings'
resources :agencies, except: [:index], controller: 'calls/agencies'
resources :incidents, except: [:index], controller: 'calls/incidents'
resources :complainants, except: [:index], controller: 'calls/complainants'
end
end
And finally the output for Rake Routes for the custom action is:
unit_responding_update_call_responding PATCH /calls/:call_id/respondings/:id/unit_responding_update(.:format) calls/respondings#unit_responding_update
I know its probably only a small problem, ive looked at similar StackOverflow Questions, treehouse forums and code academy resources but can not for the life of me sort this one out..
Thanks in advance for your assistance. Please lte me know if you require anything further for information.

however it only updates the first id, in the nested element.
this is caused by
<%= link_to "Responding", unit_responding_update_call_responding_path(call_id: #call.id, id: #respondings.first.id), method: :patch %>
As this button is displayed with in a <%= #respondings.each do |responding| %>, replace with
<%= link_to "Responding", unit_responding_update_call_responding_path(call_id: #call.id, id: responding.id), method: :patch %>

Related

Not showing created blog entries

I'm fairly new to Rails and learning to create a blog using this tutorial. On step 10, once I define create and show, after creating a new post in browser I don't see any entries on show with id page. All I see is heading and and blank title and post header.
Following is my controller -
class PostController < ApplicationController
def index
end
def new
end
def create
#post = Post.new(params[:posts])
#post.save
redirect_to #post
end
def show
#post = Post.find(params[:id])
end
end
Show view ---
<h1>Show a post</h1>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Text:</strong>
<%= #post.text %>
</p>
Route ---
RailsBlog::Application.routes.draw do
resources :post
root :to => "post#index"
end
Form ---
<%= form_for :post, url: {action: 'create'} do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br>
<%= f.text_area :text %>
</p>
<p>
<%= f.submit 'Submit' %>
</p>
<% end %>
May be this is just a spelling mistake, but since I've recently started learning Rails, I'm unable to resolve this.
Update: I can go to particular id using
http://localhost:3000/post/1
but am only seeing blank page with view headers
The problem is here:
#post = Post.new(params[:posts])
It should be params[:post] - singular, not plural.
Also note that the best practice with form_for is to pass an object instead of symbol:
form_for #post do |f|
Then:
You don't need to specify url
You can reuse the same form for an edit action or create action (if object creation failed due to failing validation)
This however requires to initialize new object in your new action:
def new
#post = Post.new
end
UPDATE:
Also your routes are incorrect. When defining plural resources, you need to use plural form (it's more the convention than requirement, but since you're learning stick with it). So change your routes to:
resources :posts
And rename your controller to PostsController (remember to rename file name as well). restart the server and all should work.
ANOTHER UPDATE:
You also need to rename folder app/views/post to app/view/posts.
AND YET ANOTHER UPDATE:
In rails 4, you are not allowed to mass assign any params which has not been whitelisted using strong parameters. You need to tell rails which fields you allow to be assigned first - this is a security thing. You need to make some changes to your controller:
class PostsController < ApplicationController
...
def create
#post = Post.new(post_params)
...
end
...
private
def post_params
params.require(:post).permit(:title, :text)
end
end
This is the way to tell your controller that you are expecting those attributes from your form and they can be safely assigned.
I had just similar problem on the same tutorial.
The code spelling was correct and clearly accorded to examples in tutorial and BroiSatse's answer above.
The mistake was in order of private method definition.
How it was:
...
private
def post_params
params.require(:post).permit(:title, :text)
end
def show
#post = Post.find(params[:id])
end
...
The working order:
def show
#post = Post.find(params[:id])
end
private
...
Anyway, this topic was rather helpful. Thak you for your answers!

Rails 4: Routing and sharing actions between controllers? What's the proper convention?

I'm building a Todo list in rails trying to learn how it all works. I'm having an issue with calling the action of a controller from the view of another controller.
I have a TodoList has_many TodoItem and TodoItem belongs_to TodoList.
TodoList#Model
has_many :todo_items
def has_completed_items?
todo_items.complete.size > 0
end
def has_incompleted_items?
todo_items.incomplete.size > 0
end
TodoItem#Model
belongs_to :todo_list
scope :complete, -> { where("completed_at is not null") }
scope :incomplete, -> { where(completed_at: nil) }
def completed?
!completed_at.blank?
end
Routes
resources :todo_lists do
resources :todo_items do
member do
patch :complete
end
end
end
Patch generates this route:
complete_todo_list_todo_item PATCH
/todo_lists/:todo_list_id/todo_items/:id/complete(.:format)
todo_items#complete
Now I can call this path from my TodoItem views without a problem like this: <%= link_to "Mark", complete_todo_list_todo_item_path(todo_item), method: :patch %>
After adding complete/incomplete scope to my TodoItem I added the following to my TodoList show view:
TodoList#Show
<% #todo_list.has_incompleted_items? %>
<% #todo_list.todo_items.incomplete.each do |item| %>
<li><%= item.content %></li>
<% end %>
This is properly displaying the incomplete items, so I tried to put a link to mark the item complete from within this view like this:
<% #todo_list.has_incompleted_items? %>
<% #todo_list.todo_items.incomplete.each do |item| %>
<li><%= item.content %>
<%= link_to "Mark", complete_todo_list_todo_item_path(item), method: :patch %></li>
<% end %>
Now this is where I get the following error:
NoMethodError in TodoLists#show undefined method
`complete_todo_list_todo_items_path' for #<#:0x000001071cf540>
Why is this complete#action undefined from my TodoList#show view?
What is the proper convention to share actions between controllers?
Thank you for your help.
I was able to solve this problem by removing the member block from the routes file:
resources :todo_lists do
resources :todo_items do
patch :complete
end
end
Now my action route was updated to: todo_list_todo_item_complete
So from my view I had to call the new route with it's nested resource:
link_to "Mark", todo_list_todo_item_complete_path(#todo_list, item), method: :patch
Lastly I had to update my controller to locate the proper todo_item#id in the complete block:
#todo_item = #todo_list.todo_items.find(params[:todo_item_id])

How to pass param from 1 controller to another

I want to pass param from the following link in the view of Client controller
and the hash is #client, I want to pass #client.user_id, if i put (:id => #client.user_id) I am not able the get :id in the other controller Estate where I want to pass this param. What should I do ? Is there a way to do it ?(Two controllers are Client and Estate, I want to pass param from Client view to the Estate controllers create method. There is no nesting of resources here!)
<%= link_to "New Property", new_estate_path(:key => #client.first.user_id) %>
create action
def create
# #estate = Estate.new(params[:estate])
if current_user.Company.nil?
#estate = current_user.estates.build(params[:estate])
else
serve = User.find(params[:key])
debugger
#estate = serve.estates.build(params[:estate])
##estate.user_id = user_id
debugger
end
respond_to do |format|
if #estate.save
if #estate.Mgmt.nil?
EstateMailer.company_confirmation(#estate).deliver
end
format.html { redirect_to #estate, notice: 'Estate was successfully created.' }
format.json { render json: #estate, status: :created, location: #estate }
else
format.html { render action: "new" }
format.json { render json: #estate.errors, status: :unprocessable_entity }
end
end
end
The code you pasted here should work:
<%= link_to "New Property", new_estate_path(:id => #client.user_id) %>
I think the problem is, you are expecting the params in create method but where as it actually goes to new method.
If you are looking for the create method. You can do
<%= link_to "New Property", estates_path(:id => #client.user_id), :method => :post %>
But that is not the right approach to use for POST actions. The right solution would be to use button_to.
<%= button_to "New Property", estates_path(:id => #client.user_id), :method => :post %>
link_to defaults to GET and button_to defaults to POST, as those are their primary usages. You can override :method if you want them to perform other action than their default.
Simply do this
<%= link_to "New Property", new_estate_path(user_id: #client.user_id) %>
In your controller:
params[:user_id]
You problem is that the create action is a POST not a GET. The link_to will only allow GET actions.
I made class variable in the controller outside all the actions.
##key, and in the new action assigned ##key the user_id that was coming through the params, and this ##key in the create action. I don't know if its the right way to do it. But it worked like a charm !

2 instance variables of the same name in different controllers

I finished Michael Hartl's Ruby on Rails Tutorial. Now I'm working on the suggested exercises. The application he builds is basically a Twitter clone where one can post Microposts and they appear in your feed http://ruby.railstutorial.org/chapters/user-microposts#fig-micropost_created
The main page is in home.html.erb from the StaticPagesController and features a Micropost textbox where one can post Microposts. The code for the textbox looks like so:
<%= form_for(#micropost) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="field">
<%= f.text_area :content, placeholder: "Compose new micropost..." %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
<% end %>
The #micropost variable is initialized in the StaticPagesController like so:
class StaticPagesController < ApplicationController
def home
if signed_in?
#micropost = current_user.microposts.build
end
end
Now inside the MicropostsController there's a create action like so:
def create
#micropost = current_user.microposts.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_url
else
#feed_items = []
render 'static_pages/home'
end
end
My question is what is the purpose of the first #micropost variable as opposed to the second?
thanks,
mike
The first #micropost becomes available to the view rendered by the first controller method; the second #micropost becomes available to the view rendered by the second controller method. And it just so happens that the two methods are rendering the same view.
The only wrinkle is that since the second controller is conditional. If the create succeeds (passes validation and saves) then there's a redirect, so there's no proper view (although there will be in a moment, after the client-side redirect). But if it fails, then the view gets an object that contains the user-entered values as well as the validation errors which the view can then show to the user.

Rails 3 Ajax not working

I'm new to rails and ajax so I'm experimenting by building a simple app. I created a simple to do app with User and Tasks (user has many tasks). Using Devise to handle the authentication. I set up the task CRUD and implemented best_in_place (in place editing gem) and got it to work. What I wanted to do next is add ajax create and delete following some example resources such as creating a 100% ajax CRUD. After setting up all the necessary code for the create and destroy in tasks_controller, I'm getting DELETE http://localhost:3000/tasks/26 500 (Internal Server Error) as seen in the firebug console log. These are the errors printed in the console in firebug:
DELETE http://localhost:3000/tasks/26 500 (Internal Server Error)
jQuery.ajaxTransport.send
jQuery.extend.ajax
$.rails.rails.ajax
$.rails.rails.handleRemote
(anonymous function)
jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
when the destroy link is clicked and same with create. The task got deleted and created after refresh but the ajax is just not working. I spent some time trying to figure out what's wrong but don't have any luck yet so I'm hoping I can get some help here while I keep digging into it. Below are my setups:
First the controller code:
def destroy
#task = current_user.tasks.find(params[:id])
#task.destroy
flash[:notice] = "Successfully destroyed post."
respond_to do |format|
format.html { }
format.js { }
end
end
def create
#task = current_user.tasks.build(params[:task])
respond_with(#task) do |format|
if #task.save
flash[:notice] = "Task was created successfully!"
respond_to do |format|
format.html { redirect_to tasks_url }
format.xml { render :xml => #task }
format.json { render :json => #task}
format.js
end
else
format.html { render :action => :new }
format.js
end
end
end
The task list partial to display the task list and delete
<table>
<% #tasks.each do |task| %>
<tr>
<td><%= best_in_place task, :detail %></td>
<!-- <p><%= best_in_place task, :completed, type: :checkbox %></p> -->
<td><%= link_to "Destroy", task, :confirm => 'Are you sure?', :method => :delete, :remote => true, :id=>'delete' %></td>
</tr>
<% end %>
</table>
The create form (without the other view stuff):
true) do |f| %>
<%= f.label :detail %>
<%= f.text_field :detail %>
<%= f.submit %> <% end %>
This is the javascript tag for application.html.erb (include jquery.js, jquery.ujs, application.js and other not so related js files):
Lastly I'm just trying to call an alert inside destroy.js.erb and with create.js.erb:
alert("Task was deleted");
Again, the crud is working normally when refreshed, it feels like the destroy.js.erb and create.js.erb is not linked somehow. I appreciated if you can provide a few hints.
Here is the error from the console after hitting delete:
ActionView::Template::Error (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each):
1:
2: <table>
3: <% #tasks.each do |task| %>
4:
5: <tr>
6: <td><%= best_in_place task, :detail %></td>
app/views/tasks/_tasks.html.erb:3:in `_app_views_tasks__tasks_html_erb___1747031968745406293_70257861453000'
app/views/tasks/destroy.js.erb:4:in `_app_views_tasks_destroy_js_erb___3673072470672404292_70257861472560'
It looks as though you have a syntax error in the destroy action. I think you're missing an end for the respond_to block.

Resources