Rails 3 - Update multiple records with one form - ruby-on-rails

I'm trying to build a simple inventory app, and I was wanting to have a page with a list of items, with only a name label and an editable box to update the instock amount and a single update button to update them all.
My model is named item and with two fields, name and instock
I'm not sure if you need more info, thanks.
* After playing around with it, I'm able to build the form, but when I click on update, it gives the error:
Couldn't find Item with ID=edit_multiple
Here is part of my controller:
def edit_multiple
#items = Item.find(params[:id])
And here is my routes.rb
resources :items do
collection do
get :search
post :edit_multiple
put :update_multiple
end
if anyone has any pointers or help, I'd appreciate it.
thanks,

Check out these screencasts:
http://railscasts.com/episodes/165-edit-multiple
http://railscasts.com/episodes/198-edit-multiple-individually

I had the same problem, and solved it by manually describing the path to the controller action in the edit_multiple form, like this:
= semantic_form_for :isbn, :url => {:controller => 'isbns', :action => 'update_multiple'}, :html=>{:method=>:put} do |f|

Related

Manage Single Rails form to other controller with create and update action

i'm new of rails. I use rails 3.0.5 .
I have an EMPLOYEE resource, but I would like to manage it with another extern controller (emp_profile_controller).
This extern controller (emp_profile_controller) manages some actions (index, new_employee, create_employee, edit_employee, update_employee ecc.. ) .
My routes for this controller are :
controller :emp_profile do
get 'emp_profile' => :index
get 'emp_edit_profile' => :edit_employee
put 'emp_edit_profile' => :update_employee
get 'new_employee' => :new_employee
post 'new_employee' => :create_employee
get 'emp_list' => :emp_list
end
How can i use one form to handle both Create and Update actions in this controller ?
I tried with :
form_for(#employee, :url => { :controller => "emp_profile"}) do |f|
but it doesn't work.
If i manage only one action at time (create OR update), url_for works, for example :
form_for(#employee, :url => { :controller => "emp_profile", :action => "update_employee" }
but how can i handle both actions with one form ?
Thanks for your availability and I apologize if I asked a stupid question.
EDIT
For now, i solved checking if object exist in the form file, if exist i set a variable with the UPDATE action path, else, i set a variable with the CREATE action path. So in the form_for statement i use url_for with the above variable.
<% if #employee.new_record?
action = "create_employee"
method = "post"
else
action = "update_employee"
method = "put"
end
%>
form_for(#employee, :url => { :controller => "emp_profile", :action => action }, :method => method
I don't think it is the best way but it works and i can use only one form file.
As your model name and controller name are different, you can add this line to your routes
resources :employees,:controller=>"emp_profile",:path=>"emp_profile"
Change the method names of create_employee,update_employee to create and update respectively.
And change your form_for as given below
<%= form_for #employee do |f| %>
....
<% end %>
First of all, if you want to update something, this object should exist.
How do plan to find it out, I don't know (cause there different ways, depends on background).
There are 2 ways of solving this issue.
You can just check if object exist in view file, and if exists, renfer form for update, else for create.
Other way is to do it in controller.
For example:
def create
#employee=Employee.find_by_name('Jack Black') #for example
if #employee!=nil
render :action=> 'update'
else
#employee=Employee.new(:employee)
#employee.save
end
as i understand you want to execute two different actions on the same controller using a form submitting, this is not possible, you can only execute one action using a form submitting,
because the form is reaching to an action controller that action is suppose to render some view at the end of it's execution code, if it was possible to use to actions on form submitting how rails will know which view to render??? (that's why it's not possible).
if you want to do some more code execution at the controller, the right way to it is to call a method with some code in it that you want to execute, that method should be in the model,
because it is a good practice to write all massive chunks of code in the model and leave the controller as light from code as possible :-)
hope this helps.

Rails: set a value using a link

I need help trying to create a link that submits an edit form.
Let's say I have a list of objects
Object - Color - Own?
Ball - Red - false - [button]
Hat - Blue - true - [button]
Shoe - Green - false - [button]
When I click on the [button] I want to set "Own?" to True.
Routes
resources :toys
Controller
def edit
#toy = Toy.find(params[:id])
end
def update
#toy = Toy.find(params[:id])
if #Toy.update_attributes(params[:toy])
flash[:notice] = "Toy Updated"
redirect_to #toy
else
render 'edit'
end
end
View
<h2>Toys</h2>
<% if #toys %>
<% #toys.each do |toy| %>
<%= toy.name %> - <%= link_to 'Set Own', edit_toy_path(:id=>toy.id, :owned=>'true')%>
<br/>
<% end %>
<% else %>
None
<% end %>
This is all about how you setup your controller actions. I'm not totally sure I understand how you want to use yours, but I have a similar case that I'll show you which I think you should be able to adapt to your situation.
In my case, I have a menu button that sets a value in the session to either keep a menu panel open or closed across any views a user looks at.
First, you need a controller action that is going to do the work you're interested in. I created a "SharedController" which handles application-wide things that don't belong to any particular view or other controller.
class SharedController < ApplicationController
# Used by AJAX links to set various settings in shared views
def edit
session[:admin_menu] = params[:admin_menu].to_sym if params[:admin_menu]
session[:advanced_search] = params[:advanced_search].to_sym if params[:advanced_search]
render :nothing => true
end
end
This controller action can set one of two values in the session, either: "admin_menu" (boolean) or "advanced_search" (boolean). Then certain views ask whether the session value for admin_menu or advanced_search is true, and if so they show the view.
You could use the same logic. Something like:
def edit
object= Object.find(params[:object_id])
object.own = params[:own]
object.save
end
To trigger this controller action with a link you need to have a route that accepts GET requests. edit is a logical choice.
resource :shared, :only => [:edit], :controller => 'shared'
Note: I think SharedController makes more sense than SharedsController, and edit_shared_path makes more sense than edit_shareds_path, so I had to specify :controller => 'shared' in my routes.rb.
Then you just need a link to a url with params. To add params onto a path you just add them to the path helper, like so:
edit_shared_path(:key => 'value')
You can retrieve these params in your controller via:
params[:key]
Make this a link like so:
link_to 'Set Own to True for This Object', edit_shared_path(:object_id=>object.id, :own=>'true')
NOTE: It's best to do this via AJAX, so be sure to set :remote=>true. If you don't use AJAX then you need to specify a redirect in your controller for what page should be loaded after this link is triggered.
In the case of my admin menu preference link, I need a link with two possible states. I generate these using a helper:
# Shows Admin Menu Button
def admin_toggle_button
if session[:admin_menu] == :on
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :off), :remote=>true, :class => 'selected', :id => 'admin_toggle_button', :title => 'Hide Admin Menu' )
else
link_to( 'Admin Tools', edit_shared_path(:admin_menu => :on), :remote=>true, :id => 'admin_toggle_button', :title => 'Show Admin Menu' )
end
end
In a view I just call this using admin_toggle_button. You can do something similar if you like, but it's optional.
I hope that gets you on the right track, let me know if you have any questions.
EDIT: Based on your comment:
Links issue GET requests, which mean you're going to the EDIT action. See: http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
A further issue, you have resources :toys instead of resource :shared (which I used for this purpose). This means your link helper is already expecting a specific toy to edit, rather than handling a singular resource. See: http://guides.rubyonrails.org/routing.html#singular-resources
Your link would work if you changed it to be:
link_to 'Set Own', edit_toy_path(#toy, :owned=>'true'), :remote => true
... and set your edit action in your controller to the following:
def edit
#toy = Toy.find(params[:id])
#toy.owned = params[:owned]
if #toy.save!
head :ok
else
head :internal_server_error
end
end
See: http://guides.rubyonrails.org/layouts_and_rendering.html#using-head-to-build-header-only-responses
Now, be aware, you really should only do this with AJAX links, and you should normally not do it with your "real" controller. The reason is, now this is the only action that can be processed by EDIT, so your normal toys#edit view would no longer work.
You can get around this by create a new action and a new route, for instance:
resources :toys do
member do
get 'set_ownership'
end
end
Then simply take the same method above and call it set_ownership instead of edit. IE:
class ToysController < ApplicationController
...
def set_ownership
...
end
end
Hope that all makes sense.
The edit_toy_path method that your link_to method is calling is going to the edit action inside your controller. It's not going to the update method that I'm guessing you want.
Your link_to will need to change to something like:
<%= link_to 'Set Own', toy_path(:id=>toy.id, :owned=>'true'), :method => :put %>
But I question this particular approach. I don't think the variable will update correctly in the update action because it is not namespaced to the proper params[:toy] object that update_attributes is expecting. And in my quick and dirty tests I couldn't get it to namespace properly.
When I have a situation like the one that you are describing I usually setup another action, like toggle_ownership and I call that from my link_to with a :remote => true option. Then the controller toggles the attributes as desired.
Thus, my routes looks something like:
resources :toys do
member do
put :toggle_ownership
end
end
And my view looks like
<%= link_to 'Set Own', toggle_ownership_toy_path(toy.id), :method => :put %>
The controller sets the variable and renders back a toggle_ownership.js.erb file that updates the appropriate section of the page.
Hope that helps!

Rails form trouble

So, I have something of an odd controller/view setup, editing a Product model object occurs in the listings controller/view. There is a long-winded explanation for why this is, but I digress. However, when I submit the form, I get the error Couldn't find Product without an ID . What gives? Strangely, when I look at the params sent with the request, the ID attribute is assigned to the 'format' key. ?!.
The controller code is very simple. Edit Action:
def edit
#edit = Product.find(params[:id])
end
Update Action:
def update
#edit = Product.find(params[:id])
if #edit.save
redirect_to :url => listings_display_path
end
end
Here is my form_for code:
<% form_for #edit, :url => (listings_update_path(#edit)) do |f| %>
Edit, the trace:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"st17LW0S9uENaV8UBcxKUfRH67oo+r3TuFAxiPKMCEc=",
"product"=>{"brand"=>"test_brand",
"productname"=>"test_product",
"category"=>"test_category",
"regprice"=>"4",
"saleprice"=>"2",
"description"=>"description"},
"commit"=>"Submit",
"format"=>"21"}
Edit: routes.rb
resources :product do
resources :promotions
collection do
get "replace"
end
end
#listings
match 'listings/index' => 'listings#index'
match 'listings/display' => 'listings#display'
match 'listings/edit' => 'listings#edit'
match 'listings/update' => 'listings#update'
Edit: create action
def create
#product = Product.new(params[:product])
#product.user = current_user
if #product.save
redirect_to :action => 'index'
end
end
First, for an alternate approach to editing multiple records on a single view, try this railscast: http://railscasts.com/episodes/198-edit-multiple-individually
Second, this is unconventional but your whole approach is unconventional...
You can stick a hidden field in the form with the ID in it. Something like:
<%= f.hidden_field, :product, :id %>
Then check your params hash and the id will be in there. You should be able to access it in the controller using something similar to:
# untested
#edit = Product.find(params[:product][:id])
Off the top of my head I'm not sure how it will be stored in your params hash but it will be there and you'll be able to access it like any other hash attribute.
Good luck!
--EDIT--
Also, regarding your comment about lack of flexibility in Rails -- one thing I've learned is that Rails isn't inflexible, but it is highly optimized for particular conventions. The developers refer to this as being "highly opinionated" software, which means:
It can do just about anything you care to do it any way you want to do it, but...
There's almost always a "preferred" way which is better, faster (harder stronger lol).
You would save yourself tons of time and energy -- and probably have a lot of fun -- grabbing the Beginning Rails 3 book. You could work through it in a weekend, and when you were done you would have a great primer on the "Rails Way" which would hopefully help you go from "I don't get why Rails doesn't do this or that" to "I get how Rails works and how easy it is to do what I want to do by following X pattern". That's what happened for me anyhow.
Again good luck!
Try this
<%= form_for #edit, :url => listings_path(#edit), :html => {:method => :put} do |f| %>
You need to fix the routes that are for a single product instance to have the id:
match 'listings/index' => 'listings#index'
match 'listings/:id/display' => 'listings#display'
match 'listings/:id/edit' => 'listings#edit'
match 'listings/:id/update' => 'listings#update'

One model and Many edit views

I have a model I named User, and I want use two different Views to edit it: the usual edit view and another view I called edit_profile.
I had no problem in creating routing, controller and views: I added edit_profile and update_profile views, and I added on routes.rb the line:
map.resources :users ,:member => {:edit_profile => :get, :update_profile => :put}
The problem is: when I submit the form in edit_profile and some error occur in some input fields, rails reload the edit_path page instead of edit_profile_path page !
This is the form on edit_profile.html.erb
form_for(:user, #user, :url => {:action => :update_profile}, :html => { :method => :put} ) do |f|
f.text_field :description
f.text_area :description
f.error_message_on :description
....
....
f.submit 'Update profile'
After clicking Update profile, if input errors occur I want to show edit_profile view instead of edit view
Where is the problem ?
Do You have some ideas ?
many thanks
Adding extra actions to a RESTful controller is often a code smell, an indication that there's a better way to model what you're trying to do. In this case, profile is really a sub-resource of user:
map.resources :users, :has_one => :profile
making your profile routes like
GET /users/1/profile # show
GET /users/1/profile/edit #edit
PUT /users/1/profile # update
DELETE /users/1/profile #destroy
You will have a separate ProfilesController for these actions... much cleaner.
How you model the data is up to you, (you don't have to have a one-to-one correlation between your models and your controllers!), but in this case I'd probably use ActiveRecord's aggregations to model the relationship between User and Profile. Think of it as an embedded has_one: http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html
Note that adding additional actions to RESTful controllers isn't always "wrong" ... its up to you to determine when its appropriate to split off the new actions into a separate resource. In this case, however, I think it's very clear-cut!
Your controller's action (the edit action, I assume) will need to know whether it has been reached via the normal edit page or the edit_profile page. You can use a hidden field named, perhaps, profile to post a breadcrumb that will tell it that. By doing this, you can redirect conditionally based on the existence of a profile param.
A cleaner way is to create a new action called edit_profile and extract the editing code to a common method that is called from both edit and edit_profile let the public methods handle any redirects.
Take a look in your user_controller file's update method. That's where submitting the edit form takes you. You'll see there that if the record can't be updated, it redirects back to the edit method.
One way to do what you want is to make your edit_profile form point to a new method, perhaps called update_profile, which is the same as the edit method but redirects to edit_profile when the record can't be saved.
Perhaps a better and DRY-er way to do it would be to pass a parameter from the edit_profile form that you can detect in your existing update method to differentiate between update attempts coming from edit / edit_profile.
Good luck!

Ruby on Rails passing of parameters between views from link_to tag instead of submit_tags (having both on page)

I'm creating in my index page of my ruby on rails program, a list of the most commonly searched for terms in my database and hence each time a user selects a specific category this is written to another database.
What i would like it to create a hyperlink and pass a certain amount of parameters to a form like is usually done with a select_tag but instead with just a hyperlink, i would like to pass a set of hidden fields that i have on the page as well as what the user has selected.
To give you a better idea, basically i have the following structure in my program:
User inputs a search on (index.html.erb), user clicks on submit tag
action, user is taken to search.html.erb page and is displayed a set of refined categories + some fields, submit button,
user is taken to closest.html.erb (which uses parameters from the previous form by invoking the params[:searchSelected] and a few other params. )
I would also like to add this functionality:
Mimick this same operation, but instead of going in the search.html.erb, i would click on an already refined search category on the index.html.erb page (from a link_to , transmit as parameters which link_to the user has chosen + the hidden fields.
i Currently have this code
#stats.each do
|scr|%>
<%= link_to scr.category, :action => 'closest', :id => scr.category%>
I'm not sure if this is relevant, but i currently have the following routes in my routes.rb file
map.resources :stores, :collection => { :search => :get }
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
would anyone please assist me please? this is my first ruby on rails project and i would really like to find a way around this please
I am not sure if this is what you were thinking, but you can add additional parameters to the link_to tag. They are then available in your controller. So:
<%= link_to scr.category, :action => 'closest', :id => scr.category, :other_param => "test" %>
Will be available in your controller.
def closest
params[:other_param] == "test" #this will be true
end
i managed to resolve this by taking the params[:id] and then according to the value either set my own values (instead of the hidden ones in the index.erb which i had set manually anyway) and otherwise, continue as usual had i placed a regular search
View:
<%= link_to obj.ptc_devicename ,"/wiuconfig/hd?idval=#{obj.id.to_s}&val=#{#devicetype}",:value => obj.ptc_devicename,:id =>obj.id %><br/>
Controller:
#Heading= params[:val]
#id=params[:id]
value will be id is 2 and val is #devicetype

Resources