how can I add a new action to a controller? - ruby-on-rails

I used the following in routes to add a new action to my Email controller:
map.resources :emails, :member => { :newfwd => :put}
The expected result was that newfwd_email_path(:id => 1) would generate the following urL: emails/1/newfwd
It does. But I get an error, it treats '1' as an action and 'newfwd' as an id. I want '1' to be interpreted as the id for emails, upon which the newfwd action acts.
I'm not sure what I'm doing wrong. (Note: I am using Rails 2.3.8)

Try
link_to newfwd_email_path(1), :method => :put
:id => 1 is as good as 1 ;)

you do not need to pass a hash to the newfwd_email_path method. Try
newfwd_email_path(1)
EDIT: you also need to use :method => :put to ensure that the PUT verb is used when request is received on the server and routing comes into effect.

Related

How to create an arbitrary link in Rails?

link_to and helpers use the names of my models and their IDs while I want to have a couple of different, arbitrary, variables in my link. I have no problems to route them, I actually keep the default routing as well, but I suddenly stuck that I cannot easily generate an arbitrary link. For instance I want to have a link like ":name_of_board/:post_number", where :name_of_board and :post_number are variables set by me, and when I use link_to I get instead "posts/:id", where "posts" it's the name of the controller. While it's not hard to use an arbitrary id like
link_to 'Reply', :controller => "posts", :action => "show", :id => number
I cannot get how I can get rid of "posts". So, is there an easy way to generate a link by variables or to convert a string into link? Sure, I can add other queries to the line above, but it will make the link even more ugly, like "posts/:id?name_of_board=:name_of_board".
You can create additional routes for your posts resource in your routes.rb, or make standalone named routes:
resources :posts do
get ':name_of_board/:id' => 'posts#show', as: :with_name_of_board
end
get ':name_of_board/:id' => 'posts#show', as: :board
Now this
#name_of_board = "foo"
#post_id = 5
link_to 'Reply', posts_with_name_of_board_path(#name_of_board, #post_id)
link_to 'Reply', board_path(#name_of_board, #post_id)
would link to /posts/foo/5 and /foo/5 respectively.
You should first edit your route entry, for example a classic show route is the follow:
get "post/:id" => "post#show", :as => :post
# + patch, put, delete have the same link but with different method
And you can call it with the following helper
link_to "Show the post", post_path(:id => #post.id)
You can edit or create a new entry in the routes, applying the parameters you want to use, e.g.:
get "post/:id/:my_platform" => "post#show", :as => :post_custom
Then
link_to "Show the post with custom", post_custom_path(:id => #post.id, :my_platform => "var")
Finally, the link generated for this last entry is for example:
"/post/3/var"
Even in this situation, you can add some other params not defined in the routes, e.g.:
link_to "Show post with params", post_custom_path(:id => #post.id, :my_platform => "var", :params1 => "var1", :params2 => "var2")
=> "/post/3/var?params1=var1&params2=var2"
RoR match your variable defined in the routes when you render a link (remember that these variables are mandatory), but you can ever add other vars that come at the end of the url ("?...&..")

Generate the URL for a generic path with possible options in Rails

I'm creating a customisable nav menu for our site and have run into the following problem.
I need to generate a URL to any controller and action on the site and optionally pass it parameters. I was able to do the former by simply saying:
url_for(:controller => nav[:controller_name], :action => nav[:action_name])
which is great for sending you to {controller}/{action}. eg. news/articles
Throwing options in suddenly changes the game. Now I need to send you to something like:
{controller}/{action}/{category}/{slug}/{id}
eg. news/articles/world-domination/montana-max-vows-revenge/12345
the helper for the above would be something along the lines of:
news_article_path('world-domination', 'montana-max-vows-revenge', '12345')
and I haven't been able to replicate that in a vanilla url_for due to the arguments.
What I have done, and I don't really like is:
url_for(send("#{nav[:controller_name]}_#{nav[:action_name]}_path", *nav[:options]))
which generates the helper using send and then passes it a kwargs list. I'm sure there's a better way to do that surely?
You can do this cleanly if you are able to name the options (split here over lines for legibility):
url_for({
:controller => nav[:controller_name],
:action => nav[:action_name]
}.merge(nav[:options] || {}))
where
nav = {
:controller_name => 'news',
:action_name => 'articles',
:options => {
:category => 'world-domination',
:slug => 'montana-max-vows-revenge',
:id => '12345'
}
}

Rails named route and parameters

I want to send to my controller some data, and then in variables:
params[:oem_number]
params[:id]
and see there some data, but how can i send to method data? How to write this route?
Now i have such route:
match '/articles/by_oem/:id&:oem_number' => 'articles#articles_by_oem', :as => :articles_by_oem
And try to create link:
= link_to "аналоги", :articles_by_oem(:id => no.article_nr, :oem_number => no.oem)
But i get SyntaxError errors...
So how to solve my problem? Please don't send me to rails doc's...
Just how to create link, that will send this two params, and also before edit route...
first, you don't need that list of parameters on a route.
You can leave just this in your routers.rb:
/articles/by_oem/:id
And, then, what are you trying to do here?
:articles_by_oem(:id => no.article_nr, :oem_number => no.oem)
:articles_by_oem is a symbol, not a function. Use articles_by_oem_path method instead:
= link_to "аналоги", articles_by_oem_path(:id => no.article_nr, :oem_number => no.oem)
= link_to "name", articles_by_oem_path(no.article_nr, no.oem)

Generating a form that passes multiple parameters

I have the following in my routes.rb
map.diff 'posts/:id/diff/:from/:to', :controller => "posts",
:action => "diff", :conditions => { :method => :get }
And I have the following in my view file.
- form_tag(diff_path(), :method => :get) do
= text_field_tag(:from, "")
= text_field_tag(:to, "")
= hidden_field_tag(:id, #post.id)
= submit_tag("Submit")
I would like to generate a form that submits something like "http://example.com/posts/3/diff/13/18", but it fails. How can I make such a form?
I need to pass parameters for diff_path(), but I don't know how to do that. I don't even know if this is possible with form_tag.
The error message:
diff_url failed to generate from {:action=>"diff", :controller=>"posts"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: ["posts", :id, "diff", :from, :to] - are they all satisfied?
To my knowledge, what you're trying to accomplish can't be done with just an HTML form. The reason being that the form will only know how to submit traditionally via GET and POST. It has no knowledge of the structure of the URL.
You get that error message because the :id, :from and :to parameters are required to form the both you want, so when you call diff_path() it freaks out.
Personally, I would advise you not to use the URL structure you're planning on - however I'm not totally clear on what this page is going to display. Regardless, if the :from and :to parameters are algorithmic input and not resource identifiers, I would avoid this structure.
That said, if you do want to implement this, you would either have to implement a redirect from rails or javascript.
Rails method
#some_controller.rb
redirect_to diff_path(:from => params[:from], :to => params[:to])
Javascript (jQuery) method
$(function() {
$("form#your_form_id_here").submit(function() {
window.location = "posts/" + this.id + "/diff/" + this.from + "/" + this.to;
return false;
});
});
I don't think that will work by specifying the url with that format in the form. Rails tries to create the URL to submit to when you render the page, not when you submit the form. So it is not seeing those parameters when you render the page. I would recommend creating another route
map.diff_form 'posts/:id/diff', :controller => :post, :action => :diff, :conditions => {:method => :post}
You could use the two routes side by side if you need to keep the current url format.
Why are you trying to do this in the first place? I really can't think of a good reason why this would be necessary.
Your "from" and "to" variables should probably just be normal URL parameters - i.e. /posts/:id/diff?from=X&to=Y, so that you can then retrieve them in your controller with params[:from] and params[:to]
There may be a way to make Rails work this way, but you're going to have issues with it, since Rails is emphatically not meant to work this way.
I think you can use like this
diff_path(#id,#from, #to)
where #id, #from, #to are instance variables. If dont, you can specify a hash also like
diff_path(:id=>#id,:from=>#from, :to=>#to)

Why is link_to adding an id to its output when I don't pass a model id?

I'm using Rails 2.2.2 with the old school routes (i.e. I'm not being RESTful) and I'm noticing strange behavior coming from the Rails link_to method. Here is my call:
link_to("my description", { :controller => controller, :action => action }, :id => "html_id")
I want the method to produce "/controller/action" but instead I'm getting "/controller/action/id". This only happens when link_to is called while processing a request for a "/controller/action/id" URL, and the controller and action are the same as that which I pass to link_to. Example:
I'm on the page at "/controller/action" and the links on that page to "/controller/action" are properly pointing to "/controller/action"
I click a link to "/controller/action/id" and the links on the new page which should point to "/controller/action" now point to "/controller/action/id", where id is the same as the id that was in the previous request.
It seems to me like something is getting confused. There is an id in the request which triggers the link_to call but I don't want it to be referenced and I explicitly don't pass an id parameter. For the record, here are my old school default routes:
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
Any idea why this is happening and, more importantly, how to stop it? Many thanks.
link_to calls the url_for helper which calls ActionController::url_for
If ActionController::url_for is given an :action it assumes the :id of the current page.
I'm not quite sure how to fix it.
Explicitly specifying a nil id, could either work or cause it to break with a nil object error.
link_to "My description", {:controller => controller, :action => action, :id => nil}, :id => "html_id"
You might also be able to get by with a named route to your controler/action pair.

Resources