Rails, restful versus non-restful route - ruby-on-rails

Something like resources :products will create 7 different restful routes for CRUD operations for resource products. For example: products GET /products(.:format) products#index
So restful route includes only controller name within itself and :id for operation like edit, show, update, delete.So as i get this, first requirement(in rails) for route(to be precisely URL) to be restful is that route can't contain action name? Q1
Second requirement for route to be restful is that action corresponding to route must "play by restful rules" in another word, for example a GET should not leave side-effects on the server, but just retrieve data. So if i have /products(.:format) products#index and within index action i saved something into DB, than above route is just looks like restful route but in fact it isn't?
When i create non-restful routes in rails for example: get ':controller/:action/:id' i only can see difference that i must explicitly write :action, so that ":action" makes this route non-restful?
To me seems that restful in rails is everything about CRUD? An second i don't need non-restful routes at all, when i can make a bunch of restful routes with construct like following(and other similar construct)?
resources :products do
member do
get 'preview'
end
end
From this point and i'm relatively new to all of this, reading a lot about REST concept, and if im right about my first question(Q1) is that only difference between restful and non-restful route in rails?

Related

Route to /post/new instead of /posts/new in rails?

This is related to a question I asked here: undefined method `posts_path' for #<#<Class:0x007fe3547d97d8>:0x007fe3546d58f0>
I was told to switch my controllers, view etc from "post" to "posts" which fixed the issue, however if I did want to use the URL /post/new, how would I do that without receiving the "undefined method `posts_path'" error I was before?
I don't understand why it's looking for "posts_path" when my controller, model and view are all called "post".
Add this before resources :posts line/block in routes.rb file,
get '/post/new', to: 'posts#new'
When you define routes using resources :posts, by default the route to the new action is /posts/new, So to override the same you need to define custom route like I did above. Also, to search the routes, Rails scans the routes.rb file from top to bottom, whatever matches first is taken. Therefore, to override the default behaviour, I asked you to define this custom route before the default routes.
Hope that helps!
I would suggest that you take a look at Rails Routing Guide.
In short:
Because the model Post describes only one record, it makes sence to call the model Post and not Posts.
With resources :posts within your routes.rb you define that you will have multiple Post objects and you want to expose all CRUD actions with a restfull interface through your controller. Your controller is named PostsController that too makes sence, because your controller provides CRUD actions for all Post objects not only one.
Furthor more rails generate some helpers for every defined route:
posts_(path|url) returns /posts=> shows multiple posts => plural helper name
new_post_(path|url) returns /posts/new => show one post for edit => singular helper name
edit_post_(path|url)(:id) returns /posts/:id/edit => edit one post => singular helper name
photo_(path|url)(:id) => show one post => singular helper name
The route name is always plural because you are always changing the resources. For instance add a new post to the posts resources.
You can also define a singleton resource via resource :geocoder in this case you say you only have one of this thing. For singletons helpers and routes are slightly different. But I saw it until now only rarely.

How did Rails generate this path from our model and controller

Ok I kind of understand this part: CRUD verbs and actions http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
and if I go to the route file of the example I have, I also see a resources :orders in it.
But now in the view of a partial names _carts I am seeing this code:
<%= button_to "Checkout" , new_order_path, method: :get %>
What confuses me is the new_order_path ? Where did that come from? What Rails convention rule is allowing us to right this? Especially where did that "new" come from?
When you use resources :orders in the routes, Rails creates 7 routes for new, create, show, update, destroy, list, and edit. All of them are given names, and new_order_path/new_order_url is related to the new action.
These routes are described at the http://guides.rubyonrails.org/routing.html#paths-and-urls
Those path helpers are automatically generated for resources defined in your routes.rb. You can check what route helpers are available by executing rake routes at the command line. They are shown in the left-most column in the table that prints out.
The general pattern of the paths that are created are like so by default:
new_{singular form of resource}_path - Routes to new on GET
edit_{singular form of resource}_path - Routes to edit on GET
{singular form of resource}_path - Routes to show on GET, destroy on DELETE, update on PUT (Soon to be PATCH in Rails 4)
{plural form of resource}_path - Routes to index on GET and create on POST.
There's also helpers that end in _url instead of _path that provide absolute URLs instead of relative paths. The particular action that is hit in your controller depends on the HTTP verb (GET, PUT, POST, DELETE, etc.) used when visiting those URLs.

Rails controller and routes configuration for website

I have an application in RAILS, it is composed of a set of API, a basic website, and an admin dashboard.
For the API routing I have no problems, as they belong to a model and a controller and are compliant with the RAILS RESTful pattern (a controller for each model, and a method for each HTTP method).
What I'm not comfortable with is writing routes and controllers for website.
The main website is at / so the default route is root :to => "home#index"and I have
Routes for the website pages which look like
get "home/index"
get "map/index"
get "api/index"
get "cgu/index"
get "legal/index"
Which I think it is not good, as I have a controller per view and I need to define a get for each views.
Now for the dashboard I tried a different approach.
It is at /dashboard, the default route is match "dashboard" => "dashboard#index" and here is few pages as an examples
get "dashboard/index"
get "dashboard/users"
get "dashboard/users_stats"
get "dashboard/routes"
get "dashboard/routes_stats"
get "dashboard/charts"
get "dashboard/financial"
So for the dashboard I have a massive dashboard_controller, which contains a def method for each dashboard pages. IE:
#dashboard/users
def users
#users = User.all
respond_to do |format|
format.html {render :layout => 'dashboard'}
end
end
the controller of the dashboard is at /controller but for views and assets I have put it in /folder/dashboard/
Here is 2 questions:
What is the best way to build the home website and dashboard ? Should I have a controller per page or a global controller where I have a method per pages ? (Which I find very convenient, less code).
How should I organize my routes to avoid to set a get "something/something" for each page ?
Or it is normal with RAILS that I have a route defined for each of my page ? I'm fairly new.
EDIT:
To clarify, the dashboard is built around an existing application with API that follow RESTFul Rails pattern:
resources :users
resources :routes
But the dashboard is not tied to any existing resources, it only do stats about those resources.
If you have custom controller action names, then yes, you'll need to define every route. If you use Restful routes, then you can define them easily as
resources :users
which will automatically create routes for actions: index, show, edit, update, create and destroy.
This might be helpful: http://guides.rubyonrails.org/routing.html
For your dashboard, which probably is bringing together a lot of resources, so they'll probably be custom methods. I'd suggest focusing on building your app by individual resource. Then, once you've defined them all, build your dashboard.
I agree with everything that other people have said here. You should definitely try to be more RESTful and create more routes like this:
resources :users
However, there is usually a controller that is not RESTful (usually called pages or static) that serves pages such as Privacy, About Us, etc, etc. For those routes, I usually do this:
['api', 'privacy', 'us'].each do |p|
get p, :controller => 'pages', :action => p
end
check this guide out if you haven't;
I think you haven't embraced the MVC concept of Rails.
For example, say you have "users". You should have users_controller.rb, users.rb (model), /views/users (view) under the app directory.
users_controller contains the index, show, create, etc default actions and your custom actions like stats
user.rb contains instance/static/helper methods
/views/users/ contains templates that corresponds to actions in the controller.

Rails3: Appropriate use of routing and resources

I've recently joined the world of Rails app development (Rails3) and I may be abusing resourceful routing.
The default resourceful routing makes some really convenient helper methods for the URLs which I use constantly. My problem is that I have controllers that I specified the routing as resourceful simply to take advantage of those helper methods. I have some basic site navigation that has no business with resources.
resource :home do
member do
get 'main'
get 'about'
get 'login'
get 'help'
end
end
Is there a better way to do what I've been doing? Anything that doesn't require that I manually add routing entries each time I have a new controller action?
Just to clarify, I want to specify routing for a controller without having to explicitly add any new actions but I also want it to auto-generate helper methods. So far, I have to explicitly add routes for each action I want that for. I can get something similar by doing this (in a non-resourceful way),
match 'home/about' => 'home#about'
But I don't want to have to write that very every route that doesn't fall into the convention.
Here's another simpler one. Just add a generic route to the bottom of your routes.rb
match ":controller/:action"
and it will map directly to the specified action of the specified controller. You can be a bit more specific if you like. For example, using get instead of match to restrict to HTTP GET requests, specifying the applicaple controllers etc.
get ":controller/:action", :constraints => { :controller => /home|help/ }
You can look into your controller for public instance methods and generate routes automatically.
# routes.rb
HomeController.public_instance_methods(false).select{|m| !(m.to_s =~ /^_/)}.each do |m|
match "home/#{m}", :action => m, :controller => HomeController, :as => "home_#{m}"
end
This will take the explicit(non-inherited) public instance methods from your controller, and select the ones that don't begin with an underscore(because underscored ones are generated methods for filters, the rest are actual actions). Then it will generate a named route for each.
Keep in mind that routes.rb is processed only at server startup so you will have to restart the server after you add new actions.

Rails 3 Routing resources scoped to a username

I have a basic understanding of rails routing, but nothing too advanced. So far I've gotten by using the RESTful resource based routes and a few custom named routes.
I am nearly done my app now though and I wanted to make some pretty urls.
In my app, each user has many pages. What's the best way to make the URL's look like www.sitename.com/username/page_name?
This will route to the pages controller's show action. Params hash includes :username and :page_name.
match "/:username/:page_name" => "pages#show"
Remember to put it last or it will match pretty much everything.
I'm not quite sure what you're using this for, but something like this might work in your routes file:
resources :users do
get 'page_name'
end
Which will produce: users/:id/page_name
You might want to check out the Railsguide on routing.
What you are looking for is a member route (section 2.9.1).
resources :users do
member do
get :cool_page
end
end
Will result in /users/:id/cool_page

Resources