undefined method `update_attributes' in ruby on rails - ruby-on-rails

This update process something different I need update query inside loop, but showing this error:
undefined method `update_attributes'
This is code:
<%= link_to "Accept", apply_path(accept:{:accept => 1}), :method => :put, class: "btn btn-success" %>
Controller:
def update
#accept = Applied.where(params[:applied_id])
params.permit!
if #accept.update_attributes(params[:applied_id])
#flash[:notice] = "updated"
render 'apply'
else
render 'apply'
end
end
request parameters:
{"_method"=>"put",
"authenticity_token"=>"Yk26LKrW9ulRVV6p8GWhqTP7coSg96JiAmU4CUYYFugBgTDR2iRZZlyY1SQ7TbA7B2YVmgulgcWTosXvjnPXZw==",
"accept"=>{"accept"=>"1"}}
How can I reach solution?

You can call update_attributes for a single model instance (a record) only not for an ActiveRecord::Relation object (it's like an array of records).
Use:
#accept = Applied.where({applied_id:params[:applied_id]}).first
or
#accept = Applied.find(params[:applied_id])
Be aware, find looks for your applied_id in the id field of your model table, if you haven't another config in place.
And note that update_attributes consumes a hash of "field:value" pairs ({field_1_name:field_1_value, field_2_name:field_2_value}) you want to update, not a single applied_id only.

You line
#accept = Applied.where(params[:applied_id])
returns an ActiveRecord relation which obviously does not have a method update_attributes. To fetch single record, use first of find instead:
#accept = Applied.find(params[:applied_id])

Continuing from our comments.
I am not sure what actually accept is and what actually you want to do specically, however, just as per my understanding, try to update your link href. It should look like:
apply_path(accept:{:accept => 1, applied_id: YOUR_APPLIED_ID})
Update your action as follow:
def update
accept = params[:accept] # Recommendation: you should use strong parameter
#accept = Applied.where(accept[:applied_id])
params.permit!
#accept.update_attributes(accept)
render 'apply' # You don't need any condition, as you are rendering same template in every case.
end

The issue is that you're trying to update a collection (where) which does not have the update_attributes method available.
What you need is .find:
def update
#accept = Applied.find params[:applied_id]
#accept.update applied_params
render 'apply'
end
private
def applied_params
params.require(:accept).permit(:accept)
end
However, you're not passing any applied_id parameter (so the find won't work); you need to use the following route:
#config/routes.rb
resources :applied do
put :apply, action: :update #-> url.com/applied/:applied_id/apply
end
<%= link_to "Accept", apply_path([[[applied.id]]], accept:{:accept => 1}), :method => :put, class: "btn btn-success" %>
A much better way would be to use button_to:
<%= button_to "Accept", apply_path([[applied_id]]), method: :put, params: {accept: 1} %>
If you used the above, you'd have to change your params method in your controller.
--
If you wanted to use .where (for multiple records), you'll need to use update_all:
def update
#accept = Applied.where id: params[:applied_id]
#accept.update_all applied_params
render 'apply'
end
private
def applied_params
params.require(:accept).permit(:accept)
end

Related

I want to approve the comments made. Ruby On Rails

I have an Approved column in a database which is false by default and might become true on "Approve" button click.
That's what this button look like at the moment:
<%= link_to('Approve It', #comment_path, method: :update) %>
But it raises an exception:
No route matches [POST] "/books/4/comments/6
# app/controllers/comments_controller.rb
def update
#comment = Comment.find(params[:id])
#comment.approve = true
redirect_to '/dashboard'
end
# config/routes.rb
resources :books do
resources :comments
end
How can I fix it?
link_to has to point to an existing route/action, with a proper method name. There is no :update HTTP method.
FYI: Approve action doesn't seem like it belongs to the #update method/action. You might want to extract it to a separate route like so:
resources :books do
resources :comments do
post :approve, on: :member
end
end
this is more idiomatic/common approach in Ruby because #update is usually preserved for more general object updates.
For this you will need to change :method argument value to :post and update your route/#comment_path.
Rails-ujs event handlers - this link might be useful for understanding how it works behind the scenes.
Controller Namespaces and Routing
Post / Update actions require forms
You're using a link_to. This is good for GET requests, but is no good for POST/PATCH/UPDATE requests. For that you'll have to use a form in HTML. Luckily Rails offers some short cut. You can use something like button_to:
<%= button_to "Approve", { controller: "comments", action: "update" }, remote: false, form: { "id" => #comment.id, "approved" => true } %>
This creates a form for you. Which will come with CSRF protection automatically. You can style the button however you like.
or you could use a link to:
<%= link_to comment_approved_path(#comment), method: :put %>
but then you would need to create a separate "approved" action in your controller, and a separate route to reach it.
(The above code has not been tested).
#html
<%= link_to "Approve It", book_comment_path(#comment), method: 'put' %>
# app/controllers/comments_controller.rb
def update
#comment = Comment.find(params[:id])
#comment.approve = true
#comment.save
redirect_to '/dashboard'
end

Rails: Hide record with button, can not find record with id error

I am implementing a method to hide records from a table but not delete from my database via a button. I added a column "revision_active" boolean attribute to my table which is set to false. With a view condition records can be shown that are only set to true.
My button(to set attributes to true via checkboxes):
<%= form_tag update_multiple_homeworks_path(:revision_active => true), method: :put do %>
....
<td><%= check_box_tag "homework[id][]", homework.id, checked = false %></td>
....
<%= submit_tag "Add to Bucket", :remote => true, :class => 'smallMobileRight button text-left' %>
In my routes:
resources :homeworks do
collection do
put 'update_multiple'
end
end
In my controller:
def update_multiple
if params[:homework][:id]
#homework_ids = params[:homework][:id]
#homework_ids.each do |id|
Homework.revision_active = true
end
else
redirect_to homeworks_homework_details_path
end
respond_to do |format|
flash[:notice] = "Added to your Bucket!"
format.html { redirect_to homeworks_homework_details_path }
format.json { head :no_content }
format.js { render :layout => false }
end
end
Params
...
"_method"=>"put",
"authenticity_token"=>"blah",
"homework"=>{"id"=>["107"]},
"commit"=>"Add to Bucket",
"revision_active"=>"true",
"id"=>"update_multiple"}
Error upon button click:
Couldn't find Homework with 'id'=update_multiple
Any ideas? I'm not catching an array of ids, error in controller? Thanks.
I am not going to give the exact answer because this is a very specific question and doesn't seem to be very beneficial to other people. I figured it's better for you to read into documentation to learn how to do that. So I will point you to some resources instead.
Your route
Looks like you are passing in update_multiple as an id, and your route helper takes an id as an argument.
Since this is updating a collection, you shouldn't be doing operation on a specific record.
You can run rake routes to find out what parameter it takes after you construct the route. (http://guides.rubyonrails.org/routing.html)
Your checkbox
<%= check_box_tag "homework[id][]", homework.id, checked = false %>
should be as below.
<%= check_box_tag "homework_ids[]", homework.id, checked = false %>
Refer to here: http://apidock.com/rails/ActionView/Helpers/FormTagHelper/check_box_tag
In your controller
What you want might be this params[:homework_ids]
Refer to here: http://guides.rubyonrails.org/action_controller_overview.html#parameters

Rails call a controller user-defined method

I am working with rails I have a controller name books and has a user defined method in it .I need to call this method so that i can see the output on console.And I dont want to call this method in helpers.
def approve
#user=current_user.users.find params[:id]
puts '#{#usery}'
end
Also I Have a link
<%= link_to 'approve',users_path,data: { :confirm => 'Are you sure to delete the folder and all of its contents?'} %>
.When i click on this link I want to call the above method on it .
You'll just need to define a route and call it through that:
#config/routes.rb
resources :users do
get :approve, on: :member
end
<%= link_to "Approve", users_approve_path(#user) %>
As #Rich suggested that, you can achieve it by member. Please note that when you'll create a member route in member block
resources :users do
member do
get 'approve'
end
end
then you'll get the params[:id]. Like
def approve
#user = User.find params[:id]
puts '#{#user}'
end
and when create a member route using :on then you'll get params[:user_id]. Like
def approve
#user = User.find params[:user_id]
puts '#{#user}'
end
Path will be same in both cases that is
<%= link_to "Approve", users_approve_path(#user) %>
Source Rails - Adding More RESTful Actions
Happy coding !!!

Delete action and destroy method

I have something like this in view:
<% if actions.include? "delete" %>
<%= link_to 'UsuĊ„', asset_path(asset), :method => :delete, :data => { :confirm => "Want to delete it?" }, :role => "link" %>
<% end %>
and this in assetcontroller:
def destroy
#asset = current_user.assets.find(params[:id])
#asset.destroy
redirect_to assets_path
end
the question is, why it "use" destroy method when action in view is "delete" ?
delete is method of HTTP protocol. destroy is the action of your controller.
Route with delete HTTP method leads to destroy action.
To edit this routes and make delete HTTP method lead to delete action (for example), you should edit config/routes.rb file.
This is because in your routes.rb file you have defined the model as a resource (or a generator like scaffold did). This means that the default CRUD routes are generated. If you want to do it another way, use your own routes instead of generating them.
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

How do I pass more than one parameter into a link_to call where I specify controller and action?

I am using a link_to to initiate a controller method that requires two parameters in order to perform the steps I need it to take. I can't seem to get the syntax right, and I'm wondering if it is because you can't pass more than one parameter in using this particular syntax. Here is what I have so far:
<%= link_to 'Select',
{controller: 'groups',
action: 'associate_subgroup_with_org',
organization_id: organization.id,
subgroup_id: #activity.group.id},
class: 'button' %>
def associate_subgroup_with_org
#organization = Group.find(params[:organization_id])
#subgroup = Group.find(params[:subgroup_id])
#subgroup.parent_group_id = #organization.id
respond_to do |format|
format.js
end
end
The link is not working and I never enter my controller action associate_subgroup_with_org. Can someone help me get the syntax right?
You can make a route like this:
get '/groups/associate_subgroup_with_org' => 'groups#associate_subgroup_with_org', :as => :associate_subgroup
And you can send any no. of parameters with link_to:
<%= link_to 'Select',
{controller: 'groups',
action: 'associate_subgroup_with_org',
organization_id: organization.id,
subgroup_id: #activity.group.id},
class: 'button' %>
Or,
<%= link_to 'Select',associate_subgroup_path(organization_id: organization.id, subgroup_id: #activity.group.id),class: 'button' %>
You need to specify it in your routes. Something like this:
get "/groups/:id/subgroup/:state" => "groups#subgroup", :as => :subgroup
And write the link like:
subgroup_path(#organization, #subgroup)
With whatever symbols you're using.
Using controller and actions in link_to/form_url is not recommended. I guess you have a groups resources, I mean in routes.rb something like resources :groups. if so then add a collection method there like:
resources :groups do
#....
post :associate_subgroup_with_org
end
Now you can use associate_subgroup_with_org_groups_path(p1: v1, p2: v2, .....)
Or you can define one named route as:
post 'groups/associate_subgroup_with_org', as: :associate_subgroup_with_org
Now you can use associate_subgroup_with_org_path(p1: v1, p2: v2, .....)
Hope its clear

Resources