I'm creating rails product controller to hide the product without deleting user grid panel using Boolean values, but I'm trying so many times, it's not working. I'm just show my code..please help where i'm missing...
I'm using ruby 2.4.1, rails 5.3.2 please help me.
rails route is,
post 'products/hide', to: 'products#hide'
products controller function is,
def hide
#product = Product.find(params[:id])
#product.hidden = true
flash[:notice] = 'you have successfully hide your product'
redirect_to suppliers_index_path
end
view form is,
<%= link_to 'delete', product, method: :hide, data: { confirm:
"Are you sure hide this #{product.Product_name} ?" } %>
products table migration are
class AddHiddenToProducts < ActiveRecord::Migration[5.2]
def change
add_column :products, :hidden, :boolean, :default => false
end
end
please help to resolve this issue.
There's a handful of things wrong with your code.
The most important issue is that you aren't saving your changes.
Your controller code which reads #product.hidden = true only assigns the value to the ruby object in memory. It does not save that change to the database. I believe this is the code you want in your controller action.
def hide
#product = Product.find(params[:id])
#product.update_attribute(:hidden, true)
flash[:notice] = 'you have successfully hide your product'
redirect_to suppliers_index_path
end
Your link_to is attempting to use a non-standard HTTP method ("hide"). I can tell that you're interpreting this as the controller method you want to hit, but that's not what method: means here. The method: parameter in link_to allows you to specify which HTTP method you want to send along with the request. HTTP methods are a standard that function as "verbs" that tell the server what you want to do to the resource you're requesting. Since you're only updating one attribute on the object, the Mozilla Foundation would instruct you to use the PATCH method for your request here.
NOTE: We'll be updating the route to match this in the next point.
COMMENT: Whoever named the product's "name" column products.Product_name needs to have a code review meeting with someone. But anyway...
<%= link_to 'delete', product, method: :patch, data: { confirm:
"Are you sure hide this #{product.Product_name} ?" } %>
Your routes need to be mapped to respond to a PATCH method request. You could use the format you use in your example, but most of the time you want to use "resourceful" routes.
resources :products do
member do
patch :hide
end
end
I will add that you don't have to use the PATCH method at all. You could also use put :hide + method: :put or post :hide + method: :post. They just need to match.
The key method passed to link_to call doesn't define controller method, but HTTP method, so it should be :post actually. You specify controller method by setting correct path/http method. You can achieve your goal by:
<%= link_to 'delete', { controller: products, action: :hide, id: product }, method: :post, data: { confirm: "Your confirmation" } %>
But I would go a little bit further and provide correct named route, assuming you have resources :products somewhere in your routes:
resources :products do
member do
post :hide
end
end
and in your view:
<%= link_to 'delete', [:hide, product], method: :post, data: { confirm: "Confirmation text" } %>
Related
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
I have this semantic nested form to destroy a nested object in Active Admin.
= semantic_form_for book.chapters.new, url: {controller: "admin/products", action: :remove_chapter} do |f|
= f.inputs do
li
label Select
= f.collection_select :chapter_product_id, book.chapter_products.order(:name), :id, :name, include_blank: 'Select Chapter'
= f.actions do
= f.action :submit, label: "Remove Chapter"
It works fine, but I feel it is wrong to use a semantic_for_for book.chapters.new since I am not actually creating anything.
I am just making a dropdown select based on a collection to remove an Object.
Just looking to see if there is a better way to do this than how I am doing it now.
I was thinking of just adding a delete button in a table_for, but I can't seem to properly direct to the member_action without getting a route error even though I use the exact same route as the controller in the semantic_form (and added method: :post).
Tried a whole bunch of options from this thread with no success -- https://github.com/activeadmin/activeadmin/issues/53
Thanks!
I just thought of it from a different simpler angle.
I linked to the nested resource's destroy directly, instead of trying to make a member_action in the mother object.
table_for product.chapters do
...
column(:delete) { |c| link_to 'Delete', admin_chapter_path(c), class: 'member_link', method: :delete, 'data-confirm': "Are you sure you want to delete this?" }
end
And since I wanted to be redirected back to the same page I came from I just hacked into the controller method on the nested Object's page and managed my redirects from there.
ActiveAdmin.register Chapter do
actions :index, :show, :destroy
controller do
def destroy
...
redirect_back fallback_location: admin_chapter_path, notice: "Message"
end
end
end
I have a simple custom method
def delete(foo, bar)
#foo = Foo.find(foo)
#bar = Bar.find(bar)
destroy
end
And I want to call it from a view with the link:
<%= link_to 'Delete', delete_articles_path(number: #number, tag: #tag), method: put, data: { confirm: 'Are you sure?' } %>
The route:
resources :articles do
collection do
put '/delete', to: "articles#delete", as: "delete_article"
end
end
I tried like here(Stack Overflow) But it says that we should pass data through params, while I want to pass it to the method as variables.
You don't need arguments. Simply pass the variables you need via the params hash.
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
i was wondering how someone can pass hidden fields in a link_to performing a delete request. i have..
<%= link_to "delete", feed_item, method: :delete,
confirm: "You sure?",
title: feed_item.content,
user_id: user_id %>
<% end %>
ive been trying to pass user_id into my controller's destroy action but it cant seem to find params[:user_id]
it seems like its possible to pass hidden values when the method is a :post, but how can i do so in a :delete?
i essentially just want the user_id in my destroy action, so it can redirect back to the users profile page.
thank you
The proper way would be to either put feed_item under user resource or user current_user method in the controller
if you decide to put it under user resource the modify your routes file as
resources :users do
resources feed_items, :only=>[:destroy]
end
and than in your link to delete change the path to
user_feed_item_path
Alternatively if you have current_user method from using any sort of authentication solution you can just use that in your redirect path