How to handle similar urls in rails 4 explicitly - ruby-on-rails

i am trying to make more semantic url like below:-
//with one params
get 'location/:location' => 'home#show_by_location', as: :show_by_location
//with two params
get ':location/:name/' => 'home#show_details' , as: :show_details
they are almost similar but they are not working as second url never gets called as rails think they are same and hence calls only first one(as expected).So how can i treat both of them differently.
Thanks in advance.

Swap the order and use a constraint to tell rails that :location cannot be the string 'location':
get ':location/:name/' => 'home#show_details', constraints: { location: /^(location)/ }, as: :show_details
get 'location/:location' => 'home#show_by_location', as: :show_by_location

Related

What is the right Rails route for passing in a different parameter than id, to return a JSON User object? Controller method provided

EDIT: This is Rails 4
Rails code in the users_controller.rb file
def showobjectdata
#users = User.all
#user = User.find_by(:username => params[:username])
render :json => #user
end
I have been trying lots of routes, but (add the "localhost" part to the beginning of this URL) /users/showobjectdata/existingusername in my browser
returns null.
Please Note: I am able to render JSON data about all users or a specific user, if I look up the user some other way than passing in a parameter which is not an id in the browser's URL field. Like in the controller method I can specifically look up a user by a specific email address. And users/show/:id renders the JSON user data of that id, because I have defined the show controller method to render JSON user data (for now).
Here is an example of a route I tried in my routes.rb file:
match 'users/showobjectdata/:username', to: 'users#showobjectdata', via: [:get, :post]
I tried various combinations with plain GET, plain POST, nested parentheses, etc. I always get null except for plain POST which doesn't work.
Try this
match 'users/showobjectdata/:username', to: 'users#showobjectdata', via: [:get, :post], param: 'username'
This is the right answer.
Basically, my username parameter (firstname.lastname) was not being passed as a full string. It is was being passed as firstname instead of firstname.lastname, with the Rails application considering "." to be where the format parameter started ('lastname' was considered a format input in the passed in parameters). I saw these passed in parameters appear in my browser ironically only when I got another error trying something new (basically my application was not responding to 'respond_to |format|' in the 'showobjectdata' method when I tried it pretty randomly - this of course led to these parameters showing up at the bottom of the screen and the googling of a solution. Yes after getting this insight on the parameters, I skipped the respond_to way and once again just rendered the json user object directly as before, without differentiating between the HTML and JSON formats).
So, basically this is the right route that worked for me:
match 'users/showobjectdata/:username', to: 'users#showobjectdata', via: [:get, :post], :constraints => { :username => /[^\/]+/ }
The controller method as originally posted is fine!
Source for the ":constraints =>" part:
Why do routes with a dot in a parameter fail to match?

How to create rails route with constrants for numbers-only that accepts empty parameter?

I have created some route like this:
get 'foo/:offset' => 'foo#action', :as => :foo, :constraint => { id: /\d+/ }
It works fine, but: I want rails to route /foo to foo#action if no parameter specified, so not only urls like /foo/123 will be routed but simple /foo too.
How can I change constraint for this? Thanks for help!
I don't know if this is the best solution, but it's a simple one:
Create a route for /foo, and another for /foo/:offset to the same controller and action!

Submit a form to a Rails route with a dynamic segment

I have a route that looks like
match 'solar_systems/:planet_num/:moon_num' => 'solar_system#moon', :as => :moon
I'd like to have a form with a select box for planet number and moon number and have it submit to this route. However I cannot use moon_path because it will have an error if the dynamic parameters are not included in it like this moon_path(4, 1). Is what I want even possible? If so, what do I give to the form tag for the route?
You don't have to use the routing helper methods, and here you can't since at the time of rendering your form you do not know the required parameters. You do, however, know the controller and action, which is really all that's needed for the destination URL. So this should work:
= form_tag('/solar_systems/moon') do
= select_tag(:planet_num, ...
= select_tag(:moon_num, ...
This should render the form tag. To process the request, you will also have to add another route so the right controller action is called:
match 'solar_systems#moon' => 'solar_system#moon', :via => :post
Or, if it makes more sense in the context of your application, you could modify your existing route to make the parameters optional:
match 'solar_systems(/:planet_num(/:moon_num')) => 'solar_system#moon', :as => :moon
See this Rails guide for more details on non-resourceful routes.
If you use this params on controller you need to specified what params is each one, btw in you helper you need to do something like this
moon_path(planet_moon: 4, moon_num: 1)
Cheers!

Managing URL Parameters in Rails

Right now I am finding routing and URL constructing within rails to be semi-confusing. I have currently matched the following for tags that are passed in when displaying/filtering data.
match '/posts/standard/' => 'posts#standard'
match '/posts/standard/:tags' => 'posts#standard', :as => :post_tag
match '/posts/standard/:tags' => redirect { |params| "/posts/standard/#{params[:tags].gsub(' ', '+')}" }, :tags => /.+/
However, now I want to add a 'skill' parameter that can only take one state; however, I am very confused by how I want to construct this within my URL. I cannot simply have...
match '/posts/standard/:tags/:skill' => 'posts#standard', as => post_tag, as: => post_skill
So, I am very confused by this at this point, does Rails offer any type of help for constructing URL's?
One way is to just keep your main route
match '/posts/standard/:tags' => 'posts#standard', :as => :post_tag
and handle the additional URL params as params. The url would look like:
/posts/standard/1?skill=something
and it is easy enough to inject the additional params, such as by
link_to post_tag_path(:skill=> 'something')
and your controller would then do
def standard
if params[:skill] == 'something'
...
else
...
end
end
Also, not sure about this, but your first line in your routes 'match '/posts/standard/' => 'posts#standard' may catch all of your routes since there is a match. If this is the case, simply move it to after the first line.

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)

Resources