Passing id in form_for action - ruby-on-rails

I have a form to update an attribute of a model - I don't want it to go to the standard update action I want it to go to a different action.
<% for car in #cars %>
<%= form_for car, :url => { :action => "custom_action/#{car.id}" } do |f| -%>
This is giving the following error -
No route matches {:action=>"custom_action/1", :controller=>"cars"}
However if I visit the url - custom_action/1 - I don't get the routing error.
Any idea why I can't do this?

In addition to what Frederick Cheung said about GET vs POST vs PUT, I think your code might be wrong in general.
To do exactly what you want, try:
form_for car, :url => {:action => "custom_action", :id => car, :controller => "cars"} do |f|
I don't think this is a good idea, and will probably cause you pain. I suggest taking a look at the Ruby on Rails Routing Guide, to understand how to do this properly. (Routing is a topic where I always have to consult the manual.)
With correct routes your code should look something like this:
form_for car, custom_action_car_path(car) do |f|
Which will be easier to change in the future if/when you refactor your app.

If you go to the url by typing it into the url bar, you're making a GET request, whereas forms emit POST requests by default, and in this case would probably emit a PUT request (since you're acting on an existing record).
It sounds like your route is only routing GET requests. Given that you say your custom action does update the record, it sounds like you should update your routes to accept PUT requests instead.

Related

Invalid route name for GET and POST

I'm working through an older tutorial that was done for Rails 3. I'm using Rails 4.1.4.
One of the instructions is to change the routes file to include the following:
get '/boards/:board_id/conversations/:id/reply' => "conversations#reply", :as => :reply_board_conversation
post '/boards/:board_id/conversations/:id/reply' => "conversations#save_reply", :as => :reply_board_conversation
Obviously that gives me an error:
Invalid route name, already in use: 'reply_board_conversation'
It seems to me that the route is somehow trying to replicate the behaviour of a new and create action. Get for new and Post for create with a single route.
The problem is I can't figure out how to rewrite the route so it works. I've googled for solutions but can't seem to find anything. If anyone could point me in the right direction it would be hugely appreciated.
It looks like the only issue is with the duplicated "named route" name reply_board_conversation. So you could simply change one. I'd probably rename the save version to save_reply_board_conversation. Then it should work. Just remember to refer to the route this way in the future. This would primarily be used in a form tag. So, for exmaple:
<= form_tag :url => save_reply_board_conversation_path do %>
Note the use of save_reply_board_conversation_path instead of reply_board_conversation_path given that the form would be submitting a POST request instead of a GET request.
The names for these routes should be different although since the composition of the URL is the same so you really only need a name for the first one.
The trick with named routes is they generate the URL only, they do not set the HTTP request method. That has to be done independently.
That means you can call the same named route two different ways:
<%= link_to('View', board_path(#board)) %>
<%= link_to('Delete', board_path(#board), method: :delete) %>
These actually render as the same URL but one will hit the GET route, the other the DELETE one.

Link_to efficiency without fetching record

In my Rails app there are experiment instances and each experiment has attachments, which are represented as binary blobs in the database and can be quite big. This question is about efficiency in coding a link_to show the attachment.
Originally I had this:
<%= link_to #experiment.attachment.file_name, #experiment.attachment %>
However I was told that the Rails app would be more efficient in rendering the page with
<%= link_to #experiment.attachment.file_name, {:controller => :attachments, :action => :show, :id => #experiment.attachment_id}, {:method => :get} if ! #experiment.attachment_id.nil? %>
The justification is that the first version fetches the attachment from the database, and the second one does not, making it is better, albeit longer and uglier. Is this true?
Both versions accomplish the same thing in directing the user to the show page for an attachment and I was under the impression the first is the default way to do a link_to a record show page.
Is there a way to shorthand the second piece of code to make it less terrible with code in the view?
Try using a rails route helper, use rake routes to view all your routes and then you can get something like this (don't forget to apped _path to route):
experiment_attachment_path(#experiment.attachment)
I would express this using the route path rather than using the ActiveRecord instance to load so the view can use its to_param method (which is what it is doing under the hood).
<%= link_to #experiment.attachment.file_name, attachment_path(#experiment.attachment_id) %>

link_to a form in ruby

I want to use the link to function to point to a form.
i.e <%= link_to 'Reports', '/reports/index.html.erb' %>
But this gives me a error saying no route matches '/reports/index.html.erb.
Thanks,
Ramya.
Rails doesn't like having the document format in the URL unless it's necessary (like when one action can handle multiple request formats). If you have reports/index.html.erb, the route to it would look like one of these:
match 'reports' => 'reports#index' #=> 'yourdomain.com/reports'
match 'reports/index' => 'reports#index' #=> 'yourdomain.com/reports/index
Then your link would be:
<%= link_to 'Reports', 'reports' %>
or
<%= link_to 'Reports', 'reports/index' %>
If you really wanted to have the .html, you could probably do it like this:
match 'reports/index.html' => 'reports#index' #=> 'yourdomain.com/reports/index.html
or
match 'reports/index.:format' => 'reports#index' #=> 'yourdomain.com/reports/index.html
But the .html is meaningless in the first case and unnecessary in the second. I don't recommend doing it this way, as it's not standard Rails practice.
I highly recommend you read this tutorial on Routing, at least the first few sections, before you move forward. It's an absolutely essential part of Rails, and if you don't understand how it works, you will never be a productive Rails programmer.
The link should point to the form from the server's point of view. Try <%= link_to 'Reports', '/reports/index.html' %> (without the '.erb')
Make sure that your routes really define that url. I guess it may be '/reports/' instead of '/reports/index.html', but YMMV.
Consult the output of command rake routes to see what routes are defined.

How call the "create" action in rails

I'm working in a rails app (rails 2.3.8), and I created a resource called articles. I need a form who call the create action in that controller. I used a form_remote_tag, but I can't call correctly the "create" action, the app always call de "new" action.
I used several different combinations, the last one is this
<%=form_remote_tag :html => { :action => url_for (:action => :create)} %>
How a could do this?.
I can't use the for_remote_for or the form_for because that form will feed more tan one table in my database.
Thanks in advance
You are over complicating it:
<%= form_remote_tag :action => :create %>
Also, be sure that this is what you truly need. You say you want to create multiple objects in the form, which is why I think you may be after form_remote_for coupled with fields_for rather than form_remote_tag, but from your question I don't fully understand.

renaming routes (map, link_to, to_param) in rails

I'm having a little issue...I setup a rails application that is to serve a german website. To make use of Rails' internal pluralization features, I kept all my models in english (e.g. the model "JobDescription").
Now, if I call "http://mysite.com/job_descriptions/", I get all my job_descriptions....so far, so good. Because I didn't want the english term "job_descriptions" in my url, I put the following into my routes.rb
map.german_term '/german_term', :controller => 'job_descriptions', :action => 'index'
map.german_term '/german_term/:id', :controller => 'job_descriptions', :action => 'show'
If I call "http://mysite.com/german_term/" or "http://mysite.com/german_term/283" I get all my job_descriptions, which is fine.
However, to make the URL more SEO friendly, I'd like to exchange the id for a more userfriendly slug in the URL. Thus, I put the following in my job_description.rb:
def to_param
"#{id}-#{name.gsub(/[^a-z0-9]+/i, '-')}"
end
which, whenever I use "job_description_path" in any link_to method, renders my URLs out to something like "http://mysite/job_descriptions/13-my-job-description-title".
However, and this is where I'm stuck, I'd like to get "http://mysite/german_term/13-my-job-description-title". I already tried to exchange the "job_description_path" with "german_term_path" in the link_to code, but that only generates "http://mysite/german_term/13". Obviously, to_param isn't called.
One workaround I found is to build the link with:
<%= link_to job_description.name, german_term_path(job_description.to_param) %>
But that's rather tedious to change all the link_to calls in my code. What I want is to replace "job_description" by "german_term" whenever it occurs in a URL.
Any thoughts?!?
Regards,
Sebastian
I think you're going to need to use the restful route helpers to get what you want.
In that case, it wouldn't take much re-factoring (assuming you've mapped JobDescriptions as a resource). Leave your to_param as is and change your JobDescriptions route to something like the following:
map.resources :job_descriptions, :as => 'german_term'
Hope this helps!
Rails only utilizes the
def to_params
end
URL builder when you are using a restful route/link helper. The only way I am aware of is to do it similar to how you did, unless you are willing to just scrap your english language links and do it all in German. In that case, just get rid of the named route lines and change the to_params to use the correct name field from the database. At that point, the REST routes should behave correctly.

Resources