How can I use methods in Rails routes? - ruby-on-rails

That's probably not the clearest title ..
Essentially, what I want to do is run the path (e.g. '/sexypage') through a function, which will do some AR lookups. If a match is found, that function will handle a redirect, which is no problem, but if not I want the routes file to carry on looking for a match as normal.
Is this possible?

It is usually done in before_action of a controller

As #Ix00st says this is normally done via a controller. You can't have complicated logic or DB lookups in your routes. Any data-dependent requests should go to standard urls like /sexypage/:some_param

Related

How to get url segment params from a given url outside of a controller in Rails?

Given a path such as
/foos/123
and a route
get '/foos/:id', as: 'foos'
How to get the ID using Rails routes (reverse) look up?
In this example, path.split('/').last would work, and a regex would be better. But how to use the Rails routes to do it?
This functionality was provided by Rails.application.routes.recognize_path but has been deprecated.
Note: This not part of a controller. Please do not answer about how to use routes within a controller.
Rails 6.
You can't. Routing is actually a lot more complicated than that.
The routes are not just a simple static set of regexes that match a string to a controller and action. You need an entire request object. You have to remember that constraints put things like headers, cookies and even middleware like Warden in the picture.
Rails.application.routes.recognize_path was depreciated since it completely failed at handling this complexity. It just gave a false sense of simplicity which is probably the worst thing software can do.

Rails exceptions to pluralising controller names?

I am building a very basic twitter-like application.
I would like to have mydomain.com/trending however I am aware that the convention would be to have "trendings" for the controller name and thus the url also - which doesn't make much sense to me, what is the best way around this, do we just mask the url some how? Or are their certain exceptions to the pluralising of controllers/views?
in your routes file do something like this
get 'trending', to: 'tweets#trending', as: :trending

Resolve Route Server Side in Rails

Just as you figure out the route when the browser hits the webpage in Rails, how would you resolve it on the server side?
For example I want to return a URL to a RESTful resource called Bookmark in an API call and want to return the 'show' action of it, and I know that:
Bookmark id: 12
Then I want to resolve it to a string:
'/bookmarks/edit/12'
so that I can get this from my Model for example.
How would I go about doing this?
Thanks!
Pretty much everywhere in the views/controllers you can use route helpers to DRY up route references.
In models, you'll need to explicitly call the route helper like so.
Rails.application.routes.url_helpers.edit_bookmark_path(id) # => '/bookmarks/12/edit'
When using the default resourceful route generator method in routes.rb like
resource :bookmarks
I'm not sure I understand - your server is the thing that's making all of those routes work - the client's browser isn't figuring out what the route is - you application is doing it.
The paths to your resources are available as helper methods at all times (at least within the controllers, and views). As such, you should return the string as the body of a response in one of your actions, in the controller that's handling your API calls.
Check your rake routes on the command line, and you'll see a list of them. In the case of your example above, it would likely be called edit_bookmark_path(12)

Non-CRUD Controller Actions

This might seem like a n00b question, but I am trying to break some of my bad practice that I may have adopted using MVC, so I hope you can help me out
So, imagine I want to do something like "Upload CSV And Parse It", it doesn't seem obvious to me to fit it into the CRUD pattern... I am not interacting with the DB, so i don't need add or update or delete, but I still want to be able to use the action in a meaningful way from different views. Thus, it is "ok" to just an action called "UploadCSV" and have it be accessible via a URL such as "/data/uploadcsv"
Your thoughts are much appreciated!
Tom
It sounds like you are talking about RESTful ideas (having actions called index, create, new, edit, update, destroy, show).
In MVC you can call an action largely whatever you want (so yes, you can call it uploadcsv if you want). If you want it fit RESTful principles you might want to think about what the action is doing (for example is a data upload essentially a create or an update function) and name it using one of the RESTful action names.
I believe I have the same point of view as you.
In my projects I try to be as restful as possible whenever I can. However as you said sometimes a special case just does not 'fit'
After all it is also a question of 'feeling'
If you provide a csv import function, I see it as perfectly correct to not create a full REST implementation for CSV.
Let's imagine in your application you have clients. And you wnat to give the option for clients to import data using csv. You can add a route for this action using:
map.resources :clients, :member => { :uploadcsv => :get }
The route is properly declared, Your 'clients' resource is completely restful and you have an additional action properly declared to manage data importation.
The only warning I have is: don't use a route like this one "/data/uploadcsv". From my point of view It lacks clarity. I like to be able to understand what my application is going to do just be looking at the url. And '/data' is too vague for me :)
The persistence of the resource is not crucial here. I suppose that what you are doing here is this - creating some kind of resource (although not persistent) out of the csv provided. The thing here is to think about what this csv file represents. What's inside? Is it something that will become a collection of resources in your system, or is it a representation of only one object in your system? If you think about it it has to be something concrete. Can you be more specific about your problem domain?

Why do I need to work harder to make my Rails application fit into a RESTful architecture?

I started a Rails project recently and decided to use RESTful controllers. I created controllers for my key entities (such as Country) and added index, new, edit, create, show, update and delete. I added my map.resources :country to my routes file and life was good.
After development progressed a little, I started to encounter problems. I sometimes needed extra actions in my controller. First there was the search action that returned the options for my fancy autocompleting search box. Then came the need to display the countries in two different ways in different places in the application (the data displayed was different too, so it wasn't just two views) - I added the index_full action. Then I wanted to show a country by name in the URL, not by id so I added the show_by_name action.
What do you do when you need actions beyond the standard index, new, edit, create, show, update, delete in a RESTful controller in Rails? Do I need to add (and maintain) manual routes in the routes.rb file (which is a pain), do they go in a different controller, do I become unRESTful or am I missing something fundamental?
I guess I am asking, do I need to work harder and add actions into my routes.rb file for the privilege of being RESTful? If I wasn't using map.resources to add the REST goodies, the standard :controller/:action, :controller/:action/:id routes would handle pretty much everything automatically.
I would treat search as a special case of index. Both actions return a collection of resources. The request parameters should specify things like page, limit, sort order, and search query.
For example:
/resources/index # normal index
/resources/index?query=foo # search for 'foo'
And in resources_controller:
before_filter :do_some_preprocessing_on_parameters
def index
#resources = Resource.find_by_param(#preprocessed_params)
end
As for index_full and search_by_name, you might look at splitting your current controller into two. There's a smell about what you've described.
Having said that, you're absolutely right that there's no point in forcing your app to user restful routes when it doesn't deliver anything over /:controller/:action/:id. To make the decision, look how frequently you're using the restful resource route helpers in forms and links. If you're not using them, I wouldn't bother with it.
If I go beyond the standard CRUD actions with my models, I normally just add the methods as required. Searching is something I add to many controllers, but not every one, so I add it and maintain the routes normally:
map.resources :events, :collection => { :search => :get }
Moving these actions to an entirely separate controller might keep some of your controllers RESTful, but I find that keeping them in context is far more useful.
REST does not specify that you can't have additional views. No real world application is going to be able use only the supplied actions; this is why you can add your own actions.
REST is about being able to make stateless calls to the server. Your search action is stateless each time as the data so far is supplied back, correct? Your alternate display action is also stateless, just a different view.
As to if they should be manual routes or a new controller, that depends on how distinct the activity is. Your alternate view, if it provides a full set of CRUD (create, read, update, delete) operations would do well to be in a new controller. If you only have an alternate view to the data, I would just add an alternate view action.
In other words, it doesn't sound like your application is failing to be RESTful, it is more an issue of realizing that the automatically generated feature set is a starting point, not a conclusion.
In my opinion they may have gone a bit off the rails here. What happened to DRY?
I'm just getting back into Rails not having done much development with it since beta and I'm still waiting for the light-bulb to come on here. I'm still giving it a chance but if it hasn't happened for me by the end of my current project I'll probably just drop-back to the old standard routes and define the methods as I actually need them for the next one.
I won't go on to explain more about REST since I think that has been answered in this question, however I will talk a little bit about the default route.
My main problem with the default route is that if you have multiple sites using the same Rails app it can look horrible.
For example there may be controllers that you don't want people to be able to see on one app:
http://example1.somesite.com/example_2/foo/bar/1
compare this to
/:controller/:action/:id
This would go to the controller example_2/foo, action bar and id 1
I consider this to be the main flaw of Rails' default route and this is something that RESTful routes (with subdomain extensions) or only named routes (map.connect 'foo' ... ) can fix.
To remain RESTful in your design, you need to rethink what you call a resource.
In your example a show action for a search controller, (search resource) is the direction to remain restful.
In mine, I have a dashboard controller (show) and controllers for single fields of in-place ecditors (show and update)

Resources