How can I pass the parameters to controller correctly? - ruby-on-rails

From show view: I'd like to pass the shown message's id to discard action and trash the message.
From index view: I'd like to pass the checked messages' ids to discard action and trash them all at once.
But I only can trash one record at once even if I check multiple and submit from index view.
How can I archive both 1 and 2 with the same action????
Routes
match 'messages/discard(/:id)' => 'messages#discard', :via => :post , :as => :discard_messages
index view
<%= form_tag(:action => discard, :via => 'post') do %>
<% #messages.each do |m| %>
<tr>
<td><%= check_box_tag "id",m.id %></td>
<td><%= m.last_message.id %></td>
<td><%= 'unread' if m.is_unread?(current_user) %></td>
<td><%= m.last_message.created_at.to_s(:jp) %></td>
<td><%= m.last_sender.username %></td>
<td><%= link_to m.subject, show_messages_path(:id => m, :breadcrumb => #box) %></td>
</tr>
<% end %>
<%= submit_tag "discard", :class => 'btn' %>
<% end %>
show view
<%= link_to 'Discard', discard_messages_path(#messages), :class => 'btn', :method => 'post' %>
controller
def discard
conversation = Conversation.find_all_by_id(params[:id])
if conversation
current_user.trash(conversation)
flash[:notice] = "Message sent to trash."
else
conversations = Conversation.find(params[:conversations])
conversations.each { |c| current_user.trash(c) }
flash[:notice] = "Messages sent to trash."
end
redirect_to :back
end

use the [] naming in your html, which rails will then make available as an array in the params
index.html.erb
<td><%= check_box_tag "message_id[]", m.id %></td>
controller
# ...
else
conversations = Conversation.where("id IN (?)", params[:message_id][])
# ...
to simplify things further I would remove the conditional in your action and create two separate actions
routes
resource :messages do
member do
post 'discard' # /messages/:id/discard
end
collection do
post 'discard_all' # /messages/discard_all?message_id[]=1&message_id[]=22
end
end

Related

Rails, form is calling wrong action

I have made my form:
<tbody>
<% #player.bases.each do |basis| %>
<td><%= basis.id %></td>
<td><%= image_tag(basis.image_url(:thumb), class: 'thumbnail') %></td>
<td><%= link_to basis.name, basis %></td>
<td><%= basis.cost %></td>
<td><%= basis.short_info %></td>
<td>
<%= form_for #player, url: {:controller => 'players', :action => :remove_detail} do |f| %>
<%= f.hidden_field :type, :value => 'basis' %>
<%= f.hidden_field :detail_id, :value => basis.id %>
<%= f.submit 'Remove',class: 'btn btn-danger' %>
<% end %>
</td>
<% end %>
</tbody>
In my routes, I have added this:
resources :players do
collection do
get 'search'
post 'remove_detail'
end
end
I have remove_detail in my players_controller.rb, and I have added this action to before_action to get current player. However when I press on my Remove button, it throws me error and tries to run update action of my controller. Why?
My before_action:
before_action :set_player, only: [:show, :edit, :update, :destroy, :remove_detail]
My remove_detail:
def remove_detail
type = params['type']
id = params['detail_id']
if type == 'basis'
basis = Basis.find(id)
name = basis.name
#player.bases.delete(basis)
end
redirect_to #player, notice: "#{name} detail is removed"
end
To fix that, try as follows:
First of all, I'd redefine your routes as follows:
resources :players do
member do
delete 'remove_detail'
end
collection do
get 'search'
end
end
This will generate proper url for deleting a detail for a "single Player":
/players/:id/remove_detail
Because of REST-y nature of Rails, we defined the url to be accessible by performing delete request.
Your form change accordingly:
<%= form_for #player, { url: { action: "remove_detail" }, method: :delete } do |f| %>
Changing your routes to use delete method is more to keep the convention of Rails. Post would make your application work too, but - its just Rails-y way.
Good luck!

Routing error in Rails embedded form

I have embedded a rails form as a simple dropdown menu in an html table. I have also implemented the form in such a way that whenever there is a change in the drop down menu then the form is submitted. But I am getting a routing error which I am trying to resolve.
The form code:
<td>
<%= form_for(lead, :action => 'update_lead_status', :html => {:id => 'lead_form'}, :remote => true) do |f| %>
<%= f.select(:status, ["to_call","called","confirmed","lite"], {:selected => lead.status}, :onchange => "$('#lead_form').submit();") %>
<% end %>
</td>
The routes.rb file:
get 'leads/:id/edit_lead_status' => "leads#edit_lead_status"
put 'leads/:id/update_lead_status'=> "leads#update_lead_status"
The leads_controller.rb file:
#PUT
def update_lead_status
#lead = Lead.find(params[:id])
respond_to do |format|
format.js
if #lead.update_attributes(params[:lead])
format.html { redirect_to leads_url, notice: 'Lead was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #lead.errors, status: :unprocessable_entity }
end
end
end
Also my embedded form in the table is at the /leads URL where I try to redirect on successful update.
The logs from my server:
ActionController::RoutingError (No route matches [PUT] "/leads/130"):
status is an accessible attribute in my leads model.
Please let me know where I am going wrong?
UPDATE:
So I tried sevenseacat's answer and it called my update_lead_status but with a wrong parameter. My table is like this:
<% #leads.each do |lead| %>
<tr>
<td><%= lead.id %></td>
<td><%= lead.prefix %></td>
<td><%= lead.name %></td>
<td><%= lead.mobile %></td>
<td><%= lead.phone %></td>
<td><%= lead.category %></td>
<td><%= lead.area %></td>
<td><%= lead.city %></td>
<td><%= lead.updated_at %></td>
<td><%= lead.is_valid %></td>
<td><%= lead.vendor_status %></td>
<td><%= lead.call_tries %></td>
<td>
<%= form_for(lead, url: update_lead_status_path(lead.id), :html => {:id => 'lead_form'}, :remote => true) do |f| %>
<%= f.select(:status, ["to_call","called","confirmed","lite"], {:selected => lead.status}, :onchange => "$('#lead_form').submit();") %>
<% end %>
</td>
<td><%= lead.remarks %><%= link_to lead.remarks, :controller => "leads", :action => "edit_lead_remarks", :id => lead, :remote => true %>
</td>
</tr>
<% end %>
Here for every row in the table it takes id as the id of the first lead in the table.
You're not specifying the action URL for the form properly - it should be for example form_for(lead, url: update_lead_status_path(lead))
(assuming you have named your route in your routes.rb, eg, as: :update_lead_status).
Try after adding following line of code in your routes.rb file.
resources :leads

How to set up routes correctly

I can untrash all the messages checked in index view without any problem.
But in show view, the link generated show the link to /messages/discard.3
this 3 could be ID.
How can I make it work? it should be linked to messages/discard/3
My files are like these
routes.rb
get "messages/received"
get "messages/sent"
get "messages/trash"
get 'messages/:id' => 'messages#show', :as => :show_messages
match 'messages/new/:username', :to => 'messages#new', :as => :new_messages
match 'messages/deliver' => 'messages#deliver', :via => :post
match 'messages/discard' => 'messages#discard', :via => :post, :as => :discard_messages
match 'messages/untrash' => 'messages#untrash', :via => :post
view 1 (index.html.erb)
<%= form_tag(:action=> discard) do %>
<% #messages.each do |m| %>
<tr>
<td><%= check_box_tag "checked_items[#{m.id}]",m.id %></td>
<td><%= m.last_message.id %></td>
<td><%= 'unread' if m.is_unread?(current_user) %></td>
<td><%= m.last_message.created_at %></td>
<td><%= m.last_sender.username %></td>
<td><%= link_to m.subject, show_messages_path(m) %></td>
</tr>
<% end %>
view 2 (show.html.erb)
<%= link_to 'Trash', discard_messages_path(#messages) %>
messages_controller.rb
def discard
conversation = Conversation.find_all_by_id(params[:checked_items].keys)
if conversation
current_user.trash(conversation)
flash[:notice] = "Message sent to trash."
else
conversations = Conversation.find(params[:conversations])
conversations.each { |c| current_user.trash(c) }
flash[:notice] = "Messages sent to trash."
end
redirect_to :back
end
You can try change it to:
match 'messages/discard/:id' => 'messages#discard', :via => :post, :as => :discard_messages
However I think what you should do is to change your all routes to:
resource :messages do
member do
#code
end
collection do
#code
end
end
It's easier to read and maintain

How to delete multiple checked records in rails?

I figured out how to display checkbox for each row.
The problem is that I can't find out how to write form_tag and submit tag in order to pass the checked rows parameter to messages_controller with using detele action.
and what to write in delete action.
Please help me out!
My view is
<table>
<tr>
<th>delete</th>
<th>ID</th>
<th>Read</th>
<th>Date</th>
<th>Sender</th>
<th>Subject</th>
</tr>
<% #messages.each do |m| %>
<tr>
<td><%= check_box_tag '', m.id, false, class: 'delete_multiple_checkbox', name: "conversations[]" %>
<td><%= m.last_message.id %></td>
<td><%= 'unread' if m.is_unread?(current_user) %></td>
<td><%= m.last_message.created_at %></td>
<td><%= m.last_sender.username %></td>
<td><%= m.subject %></td>
</tr>
<% end %>
</table>
and controller should be something like this( according to this here https://github.com/frodefi/rails-messaging/blob/master/app/controllers/messaging/messages_controller.rb)
def trash
conversation = Conversation.find_by_id(params[:id])
if conversation
current_user.trash(conversation)
flash[:notice] = "Message sent to trash."
else
conversations = Conversation.find(params[:conversations])
conversations.each { |c| current_user.trash(c) }
flash[:notice] = "Messages sent to trash."
end
redirect_to messages_path(box: params[:current_box])
end
route.rb
Example::Application.routes.draw do
root :to => "top#index"
devise_for :users, :controllers => { :registrations => "registrations" }
get 'girls', :to => 'girls#index', :as => :user_root
match '/girls/comment' => 'girls#comment', :via => :post
get "girls/show"
resources :girls
resources :home
devise_for :users do get 'logout' => 'devise/sessions#destroy' end
resources :girls do
collection do
get 'tag'
end
end
resources :contacts
resources :user_profiles
match 'messages/new/:username', :to => 'messages#new'
get "messages/sent"
get "messages/trash"
get "messages/received"
get "messages/show"
get "messages/trash"
match '/messages/deliver' => 'messages#deliver', :via => :post
end
Modify the syntax listed below to fit your requirement:
Model.where(:id => [1,2,3,4,5]).destroy_all
or
Model.where(id: params[:id]).destroy_all
All you have to do is wrap the whole messages rendering block with a form_tag and add a submit_tag wherever you'd like. I assumed your controller is MessagesController under blank namespace and the action is trash. Note that if your controller is under messaging namespace you might want to change the :controller => :messages into :controller => 'messaging/messages'.
<% form_tag :url => { :controller => :messages, :action => :trash}, :method => :delete do %>
<% #messages.each do |m| %>
<tr>
<td><%= check_box_tag '', m.id, false, class: 'delete_multiple_checkbox', name: "conversations[]" %>
<td><%= m.last_message.id %></td>
<td><%= 'unread' if m.is_unread?(current_user) %></td>
<td><%= m.last_message.created_at %></td>
<td><%= m.last_sender.username %></td>
<td><%= m.subject %></td>
</tr>
<% end %>
<%= submit_tag "Trash All Checked" %>
<% end %>
I also assumed your routes.rb accepts a HTTP DELETE method for the specified route. You can check that with rake route | grep messages and verify the route is set.
If it is not you will have to add it with:
resources :messages do
collection do
delete :trash
end
end

Simple quantity function problems, shopping cart

I just picked up Agile Web Development with Rails 3rd Ed., and I'm going thru the Depot Application chapters, I'm attempting to create a simple Edit quantity function, and delete function. I've had luck with the delete function but no luck with the edit quantity function.
I'm going to provide a lot of information, so please don't feel overwhelmed. I've found this to be a challenging problem.
To add_to_cart.html.erb
<div class="cart-title">Your cart</div>
<table>
<% for item in #cart.items %>
<tr>
<td><% form_for #cart.items, :url => {:action => "cart_update", :id => "#{item.getinventoryid}"} do |f| %>
<%= f.text_field :quantity, :size => '3' %>
<%= f.hidden_field :id, :value => "#{item.getinventoryid}" %>
<%= f.submit 'cart_update' %>
<% end %></td>
<td><%=h item.quantity %> ×</td>
<td><%=h item.title %></li></td>
<td><%=h item.description %></td>
<td class="item-price"><%= number_to_currency(item.price) %></td>
<td><%= link_to 'remove', {:controller => 'inventories', :action => 'remove_cart_item', :id => "#{item.getinventoryid}"} %></td>
</tr>
<% end %>
<tr class="total-line">
<td colspan="4">Total</td>
<td class="total-cell"><%= number_to_currency(#cart.total_price) %></td>
</tr>
</table>
<%= button_to "Checkout", :action => 'checkout' %>
<%= button_to 'Empty cart', :action => 'empty_cart' %>
inventories_controller:
def cart_update
#inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.increment_inventory_quantity(params[:inventory])
end
def remove_cart_item
inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.remove_inventory(inventory)
redirect_to_index("The item was removed")
end
Cart.rb model
attr_accessor :items
def increment_inventory_quantity(id, quantity)
inventory_to_increment = #items.select{|item| item.inventory == inventory}
# We do this because select will return an array
unless product_to_increment.empty?
inventory_to_increment = inventory_to_increment.first
else
# error handling here
end
inventory_to_increment.quantity = quantity
end
def remove_inventory(inventory)
#items.delete_if {|item| item.inventory == inventory }
end
cart_item.rb model
attr_accessor :inventory, :quantity
def getinventoryid
#inventory.id
end
This produces strange results:
Notice the quantity 16 appears in both items from my loop (#Fail). When I submit the form a ArgumentError in InventoriesController#cart_update wrong number of arguments (1 for 2) error is returned. Parameters being passed:
{"commit"=>"cart_update",
"_method"=>"put",
"authenticity_token"=>"sH1tWXTJPltpSq5XaAkww7259IR5ZiflnqSFB2Zb0IY=",
"id"=>"50",
"cart_item"=>{"quantity"=>"16",
"id"=>"50"}}
You are getting the wrong number of arguments error because you are passing one argument to #cart.increment_inventory_quantity in the controller method. That method requires two arguments.
# In your controller:
def cart_update
#inventory = Inventory.find(params[:id])
#cart = find_cart
#cart.increment_inventory_quantity(params[:inventory]) # you are passing one thing
end
# Then in your model:
def increment_inventory_quantity(id, quantity) # the method wants two things
# ...
Possibly you intended to do something like this:
def cart_update
#inventory = Inventory.find(params[:cart_item][:id])
#cart = find_cart
#cart.increment_inventory_quantity(#inventory.id, params[:cart_item][:quantity])
end
Are you sure it's form_for( #cart.items ) and not form_for( item )?

Resources