I am trying to have a routing rule which does the below
http://localhost:3003/tab/show#user11
when this url is loaded, the system should fetch the value after # and use it to generate user output.
I tried to add this rule in the routes.rb file
match "tab/show#:value => "tab#show"
but i could not able to use this and fetch the value after # like #current = request["value"]
Please suggest.
This part of url isn't being sent to the server during request. So, naturally, you can't get access to it on the server-side. Use javascript to access it.
And it's not Rails' "feature". It's common thing.
If you change your root to
match "tab/show/:value => "tab#show"
and use the URL
http://localhost:3003/tab/show/user11
then it will be available in the params hash:
#current = params[:value]
Unless you have a good reason for your current structure then this is the best way to do it.
Tom
Related
I'm new to rail. I have few clarifications, which I have listed below.
I have referred many links and stack overflow questions, everywhere it's mentioned to use request and fetch the details regarding the path, controller, action etc. but if I use request in my routes.rb it throws undefined local variable or method error.
I used constraints in my routes.rb and from there it calls a method matches? from a class where dynamic constraints are defined inside lib/constraints directory. In here the matches?(request) receives a parameter named request, which has details about current route, from where the parameter value is sent?, I have this doubt because while using this method inside routes.rn in constraint(ClassName) I'm not sepecifying the method name (matches?) or the parameter request
I would like to know the working of things behind the scene.
Thank You
Are you looking for it
request.url
# => "http://localhost:3000/lists/7/items"
request.path
# => "/lists/7/items"
If you have URIs:
localhost:3000/users/:id
localhost:3000/users
localhost:3000/users/new
....
You can do something like
rake routes | grep user
in order to get only those that contain user in its path name.
Hope this helps..
conventionally you don't access the current path in the routes.rb, at least as how it seems you're asking to access it. There are a number of different matching methods and techniques used in the rails router that serve the utility I imagine your looking for.
Here's a link to the docs: https://guides.rubyonrails.org/routing.html
Can you share exactly why you want to access the curret route in the routes.rb file?
How do I route to a page that ends with an id?
E.G.
before: site.com/messages/8
after: site.com/messages/terrytibbs
I've tried:
match "/messages/:username" => "messages#id"
No luck so far. Just trying to make the url have a little more meaning by replacing the number with the username of the user the current user is talking to.
Kind regards
If you want something simple without having to change your routes etc, why not do this:
class Message
def to_param
"#{id}-{username}"
end
...
end
Assuming you have a username attribute on your message. That will make your url look like:
site.com/messages/8-terrytibbs
this works because of the following (say in irb):
"8-terrytibbs".to_i
=> 8
and when rails looks up your message in your controller it will do the same thing to the id parameter.
EDIT: there is an excellent railscast on this here: http://railscasts.com/episodes/63-model-name-in-url and an updated version here: http://railscasts.com/episodes/63-model-name-in-url-revised
Take a look at friendly_id gem. I think it's what you need.
FriendlyId is the "Swiss Army bulldozer" of slugging and permalink plugins for Ruby on Rails. It allows you to create pretty URLs and work with human-friendly strings as if they were numeric ids for Active Record models.
Using FriendlyId, it's easy to make your application use URLs like:
http://example.com/states/washington
instead of:
http://example.com/states/4323454
Your route is set up correctly you have to change the Controller to use the correct parameters.
Assuming your MessagesController does:
def id
User.find(params[:id])
end
change to:
def id
User.find_by_username(params[:username])
end
I would also recommend adding indexing on user name.
You're on the right track, you just need to make sure the route is pointing at a proper action on the controller, like so:
Say the action you want this to point to is named show, here is how you would define the route:
match 'messages/:username' => 'messages#show'
Then if you navigate to messages/8, params[:username] will be set to '8' (parameters always come in as String's.
Likewise if you navigate to messages/terrytibbs, params[:username] will be set to 'terrytibbs'.
Try reading Chapter 3-3.5 of the Rails Routing Guide, it provides a good overview of how to bind parameters to a route like you are attempting to do.
Say if I have a model called 'deliver' and I am using the default URL route of:
# Install the default routes as the lowest priority.
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
So the deliver URL would be:
http://localhost:3000/deliver/123
What I am trying to work out, is how to use another field from the database alongside or instead of the ID.
For example. If I have a field in the create view called 'deliveraddress', how do I put that into the routes?
So I can have something link this:
http://localhost:3000/deliver/deliveraddress
Thanks,
Danny
Since it sounds from your comments like you're trying to obfuscate the ID in your URL, I would suggest that you look at this question, which was asked a few days ago.
Obfuscating ids in Rails app
First of all, the url "http://localhost:3000/deliver/123" matches either default routing rule. However, only after you declared an "resource" it will generate such a RESTful URL.
In your case, just implement the "to_param" method of Deliver model:
class Deliver < ActiveRecord::Base
def to_param
return self.deliveraddress
end
end
it will generate the url you want by calling url_for method, like link_to #deliver
Do not forget to make sure you have unique deliver addresses in your database so you will never find duplicated records with one address.
After that, you need to update the finder methods in actions:
def show
#deliver = Deliver.find_by_deliver_address!(params[:id])
end
Hope this answer will be useful.
I have a small rails app that has default scaffold generated routes eg. /stadia/1.xml. However I have to support legacy client app that can't construct such URLs correctly. What I need to do is to map URL in the form:
/stadia?id=1?format=xml to /stadia/1.xml
Or even something like:
/myApp?model=<model_name>?id=<id>?format=xml to /<model_name/<id>.xml
Is it possible to craft appropriate route in Rails?
I don't have good answer for this. What I would do is change first part of url to /stadia_legacy for legacy urls or change first part of urls for RESTful routes.
Then you can map in routes:
map.stadia_legacy :stadia_legacy, :controller => 'stadias', :action => 'please_redirect_me'
Then in stadias controller in action please_redirect_me you can check all params (they are availble in params hash: params[:id], params[:format] etc.) and redirect to correct url. Or you can write all routes manualy to correct controller and action.
What if you do some url rewrite in apache ?
I had a similar question. No answers so far, so it seems routes.rb config doesn't offer an easy way of doing this (routing based on query parameters), which I find surprising actually.
So an ugly workaround would be to have a 'myApp' default route, and then have a special redirecting controller which would look at the query params (because in controllers you do have access to that) and redirect accordingly.
My application is in RoR
I have an action/view called showsummary where the ID has been passed into the URL, and the controller has used that to instantiate #vendor where #vendor.name is the name of a company.
I would like the URL to be, rather than showsummary/1/ to have /vendor-name in the URL instead.
How do I do that?
All of these solutions use find_by_name, which would definitely require having an index on that column and require they are unique. A better solution that we have used, sacrificing a small amount of beauty, is to use prefix the vendor name with its ID. This means that you dont have to have an index on your name column and/or require uniqueness.
vendor.rb
def to_param
normalized_name = name.gsub(' ', '-').gsub(/[^a-zA-Z0-9\_\-\.]/, '')
"#{self.id}-#{normalized_name}"
end
So this would give you URLs like
/1-Acme
/19-Safeway
etc
Then in your show action you can still use
Vendor.find(params[:id])
as that method will implicitly call .to_i on its argument, and calling to_i on such a string will always return the numerical prefix and drop the remaining text- its all fluff at that point.
The above assumes you are using the default route of /:controller/:action/:id, which would make your URLs look like
/vendors/show/1-Acme
But if you want them to just look
/1-Acme
Then have a route like
map.show_vendor '/:id', :controller => 'vendors', :action => 'show'
This would imply that that it would pretty much swallow alot of URLs that you probably wouldnt want it too. Take warning.
I thought I'd mention String#parameterize, as a supplement to the tagged answer.
def to_param
"#{id}-#{name.parameterize}"
end
It'll filter out hyphenated characters, replace spaces with dashes etc.
Ryan Bates has a great screencast on this very subject.
Basically you overload the to_param method in the Vendor model.
def to_param
permalink
end
Then when you look up the resource in your controller you do something like this:
#vender = Vender.find_by_name(params[:id])
But the problem with this is that you'll have to make sure that the vendors' names are unique. If they can't be then do the other solution that Ryan suggests where he prepends the the id to the name and then parses the resulting uri to find the item id.
You do this by modifying the routes that are used to access those URL's and changing them to use :name, rather than :id. This will probably mean that you have to write the routes yourself rather than relying on resources.
For instance add this to the routes.rb file:
map.with_options :controller => "vendor" do |vendor|
vendor.connect "/vendor/:name", :action => "show"
# more routes here for update, delete, new, etc as required
end
The other change that will be required is that now you'll have to find the vendor object in the database by the name not the id, so:
#vendor = Vendor.find_by_name(params[:name])
Internally (at least to my knowledge/experimentation) whatever parameter name is not specified in the URL part of the route (i.e. not within the "/Controller/Action/:id" part of it) is tacked on to the end as a parameter.
Friendly ID
http://github.com/norman/friendly_id/blob/26b373414eba639a773e61ac595bb9c1424f6c0b/README.rdoc
I'd have to experiment a bit to get it right, but there's two primary parts to the solution.
1) Add a route.
in config/routes, add a line that sends requests of the form baseurl/controller/:vendor-name to the action showsummary, (or maybe a new action, show_summary_by_vendor_name)
[also, if you planned on using baseurl/:vendorname, that's fine too]
For convenience, make sure the parameter is something like :vendor-name, not the default :id
2) Write the controller action.
In the controller file, either edit your showsummary action to differentiate based on whether it's called with an id or with a vendorname, or just write a show_summary_by_vendor_name. (depending on best practices, and what route you wrote in 1. I don't know off the top of my head which is preferable)
You can then do
#vendor = Vendors.find_by_name(params[:vendor_name])
or something like that, and then render it the way you would in regular showsummary.
3) Use that as the link.
Once you confirm that baseurl[/controller?]/vendor-name works, and shows the summary, make sure all the links in your application, and elsewhere, use that link. Off the top of my head, I can't remember how difficult it is to integrate a custom route into link_to, but I think it's doable. Most search engines [google] rely heavily on links, so good SEO will have you using those named links, not the numbered ones. I think. I don't know much about SEO.
Take a look also at this quck start to SEO for Rails