Rails pass data to form for different model - ruby-on-rails

I have two models, Users and Shifts.
Users: id, name
Shifts: user_id, time_length
User has_many Shifts; Shift belongs_to User. Fairly simple.
What I want to do is add a button on my show user controller (/users/1) that links to the new Shift controller view (/shifts/new). I've managed to do this with a button, as I want to pre-populate the form with the information from my Users model (i.e. send across the user.id).
I'm using the following code, which is linking fine, but can't work out how to pass the user.id details
button_to "Create Shift", {:controller => "shifts", :action => "new"},{ :method => "get"}

You can pass in extra parameters to the second argument like so:
button_to "Create Shift", { :controller => "shifts", :action => "new", :user_id => user.id }, { :method => "get" }
This should generate a URL like /shifts/new?user_id=5.

You can use Nested resources:
In routes.rb write:
map.resources :users do |users|
users.resources :shifts
end
Then the path for the new shift form would be new_user_shift_path = /users/:id/shift/new
And in the shifts_controller you can get the user like this:
#user = User.find(params[:user_id])
Then you put it in your form as a hidden tag field. (Or it won't be necessary - I don't know exactly)

Related

How to make a custom route in Rails? By custom I mean one that reacts to params

So essentially I've setup a route to match "products/:product", which seems to respond to a page like baseurl/products/toaster and displays the toaster product. My problem is I can't seem to use link_to to generate this path, and by that I mean I don't know how. Any help on this?
There are several solutions on this one :
<%= link_to 'Toaster', { :controller => 'products', :action => 'whatever', :product => 'toaster' } %>
But it's not really Rails Way, for that you need to add :as => :product at the end of your route. This will create the product_path helper that can be used this way :
<%= link_to 'Toaster', product_path(:product => 'toaster') %>
Within your routes file you can do something like:
match "products/:product" => "products#show", :as => :product
Where the controller is ProductsController and the view is show
within the Products controller your have
def show
#product = Hub.find_by_name(params[:product])
respond_to do |format|
format.html # show.html.erb
end
end
Where whatever is in the products/:product section will be available via params.
Then, since we used :as in your routes you can do this with link_to:
<%= link_to product(#product) %>
Where #product is an instance of a product or a string. This is just an example and the param can be anything you want, the same goes for controller/action. For more info you should check out this.
Hope this helps!

Want to add links to a method of another controller in the show screen using active admin

in my active admin app i have 2 models, per example: Vehicle and Front.(Front has many Vehicles)
In the :show view of an Front, it lists all the vehicles that belong to it. And for each Vehicle it lists, it have a link "Remove" that removes the corresponding Vehicle from that Front. Here's what my code looks like:
ActiveAdmin.register Front do
show do
panel "Vehicles in this Front" do
table_for(front.vehicles) do |vehicle|
vehicle.column("id") {|vehicle| auto_link frente.vehicles}
vehicle.column("category") {|vehicle| vehicle.descricao}
vehicle.column("status") {|vehicle| vehicle.status}
vehicle.column {link_to "Remove" , remove_admin_vehicle_path(vehicle.id), :method => :post}
end
end
And the Remove method from Vehicle:
member_action :remove , :method => :post do
vehicle = Vehicle.find(params[:id])
vehicle.front = null
vehicle.save!
flash[:notice] = "vehicle removed"
redirect_to :action => :show
end
But when I click on the Remove link, theres an error: Its not sending the id from the vehicle. How can I send the id from the Vehicle?
Use delete method and destroy action, it's right way.
so..
Try to use
vehicle.column {link_to "Remove" , remove_admin_vehicle_path(vehicle), :method => :post}
And show rake routes result.

How to remember a parameter value between pages in a controller

I have managed to produce a series of three buttons on an index page enabling a user to identify a subset of the objects in a database - button 1 - type = "new", button 2 - type = "used", button 3 - no restriction i.e. can be new or used.
Currently index.html.erb contains:
<%= link_to "New", :controller => params[:controller], :action => params[:action], :product_type => 'New' %>
<%= link_to "Used", :controller => params[:controller], :action => params[:action], :product_type => 'Used' %>
<%= link_to "Don't Restrict", :controller => params[:controller], :action => params[:action], :product_type => nil %>
Within product.rb i have:
scope :by_product_type, lambda{|product_type| where(:product_type => product_type) unless product_type.nil? }
Finally I have productfinder_controller:
before_filter :load_grips, :only => [:index, :bybrand, :bycolour, :byprice]
protected
def load_products
if params[:product_type]
#productssmatchingtype = Product.by_product_type(params[:product_type])
else
#productsmatchingtype = Product
end
end
The above code works exactly as I hoped, loading all items initially and restricting them if Button 1 or Button 2 is pressed.
I would also like to have similar functionality on 3 other pages within the Productfindercontroller, namely byprice, bybrand and bycolour. I have put the same code as provided above in each of these 3 other .html.erb files and again things seem to be behaving...
EXCEPT - When a new page is loaded the default is that all the products are shown, i.e. it has not remembered what button the user pressed on the previous page. Is it possible to store the information regarding the button pressed somewhere which is accessible to all the pages in the controller? Similarly / Alternatively, is it possible to define #productsmatchingtype (in productfinder_controller) in such a way that it is accessible to all the pages and doesn't need to start from scratch again?
You cannot remember variables beetwen requests. However you can store product_type in session:
def load_products
#get product_type from session if it is blank
params[:product_type] ||= session[:product_type]
#save product_type to session for future requests
session[:product_type] = params[:product_type]
if params[:product_type]
#productssmatchingtype = Product.by_product_type(params[:product_type])
else
#productsmatchingtype = Product
end
end
That should do the job.

Rails routing model method parameter

I have the route
map.member 'members/:id/:name_url', :controller => 'members', :action => 'show', :requirements => { :id => /\d+/ }
and on my Member model I have a name_url method which takes the name and converts it to lowercase and changes spaces to dashes
the problem is that if I run
link_to "Bill", member
it gives me an "member_url failed to generate from" error
is there a way to achieve that? I was thinking a view helper that generated the link, but I couldn't access that from the controller if I needed to...
Assuming this is the show action of the MembersController
class MembersController
def show
#member = Member.find_by_name("Bill")
end
In app/views/members/show.html.erb, You'll want to use:
<%= link_to #member.name, member_path(#member, :name_url => "something") %>
The problem is the :name_url parameter in your route:
map.member 'members/:id/:name_url', :controller => 'members', :action => 'show', :requirements => { :id => /\d+/ }
When you pass an ActiveRecord object as an option for url_for (which is what link_to does), Rails will implicitly call the model's to_param method. Which unless overridden only returns id the id. You could override to_param, but that won't give you the url you want. Because to_param is used to create the string that replaces id in urls. The best you could do with minimum changes is settle for something like this:
members/:id
where :id is actually :id-:name_url
Really the best option is what Dan McNevin suggests. However if that's too long for you, you can always just make it a helper:
def link_to_member member
link_to member.name, member_url(member, :name_url => member.name)
end
And use it in place of link_to.
link_to "Bill", member => link_to_member member

Update row status using ajax

I am currently trying to program my first ajax interface using Rails.
The application currently shows a table populated with list items. The user has to approve or reject each of the list items. I currently have an edit link at the end of each row that shows a form in which I can approve the list item.
I am thinking on using a checkbox instead of the edit link. When the user clicks the checkbox I want to update the database with the status, user name and date/time without leaving this page.
What steps should I follow?
Can I use a checkbox or am I
restricted to buttons?
What xxx_remote helper should I use?
How can I update the checkbox state with the results of the ajax call?
I don't think that a checkbox is the correct control for what you're looking for.
You said you want user's to be able to approve or reject items which means that you have 3 states: unhandled, approved and rejected. A checkbox only supports 2 states: off and on
I would use two links accept and reject and then do it as follows.
In your view:
...
<tr id="item1">
<td>Accept or Reject</td>
<td>
link_to_remote 'accept', :action => :accept, :id => 1, :method => :post
link_to_remote 'reject', :action => :reject, :id => 1, :method => :post
</td>
</tr>
...
In your controller
def accept
item = Item.find(params[:id])
item.accept
respond_to do |want|
want.js {
render :update do |page|
page << "$('item_#{item.id}').cells[0].innerHTML = 'Accepted'"
...include other updates you need to make to your row...
page.visual_effect :highlight, "item_#{item.id}"
end
}
end
end
... similar for reject method ...
This is a comment to solution proposed by Andrew,
I had to write params of link_to_remote function like this
link_to_remote 'reject', :url => {:action => :reject, :id => item.id, :method => :post}
Also, remember to add new actions to your routes.rb if You are using restful resources
i.e.
map.resources :items, :member => {:accept => :post, :reject => :post}

Resources