I am using Ruby on Rails 3.0.9 and I would like to build a controller name from a class name as well as possible following RoR naming conventions. For example, if I have the Articles::Comment class I would like to retrieve the articles/comments string.
Maybe it exists a RoR method created by developers to handle internally these conventions, but I don't know that.
How can I retrieve the controller name as in the example above?
You're looking for the underscore method. More info here.
"Articles::Comment".underscore
Or, if you've got the controller class itself, it would be like this:
Articles::Comment.name.underscore
EDIT
As of routes, they are built one piece at a time, even when you namespace them. When you do something like this:
map.resources :articles do |articles|
articles.resources :comments
end
What rails is going to do is, first:
"articles". classify # which yields "Article" then rails is going to append "Controller" to it
Then it's going to get "comments" and do the same, but this one is going to be routed under "/articles". Rails does not namespace internal resources, so, the controller has to be CommentsController, not Articles::CommentsController.
Only then you clearly namespace something, Rails is going to namespace your classes:
map.namespace :admin do |admin|
admin.resources :articles # will require controller "Admin::ArticlesController"
end
I hope it's clearer now.
Related
Why Controller names are plural but application_controller is itself a singular.
I was just curious when i scaffold a person and rails generated a people_controller for it, I was impressed but then I saw application_controller and it is singular. Does it has an explanation or it is as it is ?
Rails is full of conventions and plural names for controllers is simply one of those conventions. It is so Rails can locate the appropriate controller when you put resources :books in your routes.rb
You can override the convention and specify the controller explicitly, resources :books, controller: "library". In this case, Rails will look for LibraryController.
With ApplicationController, you don't call it directly and Rails doesn't need to do this lookup and so it can be named whatever. You can rename it, for example.
The Survey gem is not creating the routes on my Rails app so I am wondering what to put in the routes.rb file?
I ran
rails generate survey:install
then ran
rails generate survey routes namespace:survey
and does not work.
I'm using Rails 4.2.1
The controllers are at controllers/survey/attempts_controller.rb and controllers/survey/surveys_controller.rb
The views are at survey/attempts/ and survey/surveys/
How should I put in the routes for these? Thanks.
Survey uses a standard CRUD interface, so you should be able to add resources named after the survey model you've created.
i.e. resources :surveys
If this doesn't do the trick, you can see a basic routing setup in the survey demo app here: https://github.com/runtimerevolution/survey-demo/blob/master/config/routes.rb
Let me know if this helps!
Its okay if it didn't add routes to your routes.rb file. You can add it yourself. And since you have it namespaced within Survey for your controllers you have to namespace in your routes file too.
namespace :survey do
resources :surveys
resources :attempts
get 'survey_details' => 'surveys#get_details' #this request will be handled by get_details method of SurveysController
end
Since it uses basic Create Read Update Delete in its controller, resources :surveys will take care of these. For any additional routes you want to define for your controllers make sure to put them inside the namespace block.
I am little bit confused in using rails route. I need some suggestion about customizing my url.
This is my current url
http://localhost:3000/posts/product/41?product_id=2
and
http://localhost:3000/posts/product/41?model_id=24&product_id=2
This is my link
<%= link_to product_model.name, controller: :posts,action: :product,product_id: params[:product_id],model_id: product_model.id
Logically product should come first in url. But why model prefers first here.
And i need my url something like this
http://localhost:3000/posts/product/41/mobile
and
http://localhost:3000/posts/product/41/mobile/nokia
Since i am not familiar with rails route i didn't write any special coding in my route
Here is the simple route exist
resources :posts
Ok your question here actually contains two different problems, so i will give suggestions to both.
1. Nested resources
Your first problem is to use "nested routes". Rails guide has a long and good article about routes and how to write and use them, including nested routes. You can check it out here: http://guides.rubyonrails.org/routing.html#nested-resources.
However in your situation would the solution look something like this:
resources :category do
resources :sub_category do
resources :products do
resources :models
end
end
end
You can now greate links like this
<%= link_to product_model.name, category_sub_category_product_model_path(#category, #sub_category, #product, product_model) %>
You can see that i have removed posts, see 3. Refactor design to see why. If you really want this as a action on posts, should you however do something like this (but would recommend this!):
get "posts/product/:category_id/:subcategory_id/:product_id/:model_id", to "posts#product", as: :posts_product
This would be used like this in your views:
<%= link_to product_model.name, posts_product_path(#category, #sub_category, #product, product_model) %>
2. Pretty URL's
Your second problem is to use model names instead of id's in your urls. The simpels solution for this is having a unique attribute on your model that you can use instead of id, and then just add a to_param method. Fx for product could we do something like this:
class Product < ActiveRecord::Base
def to_param
name
end
end
Ryan Bates have made a good screencast about this: http://railscasts.com/episodes/63-model-name-in-url-revised. If you want something more flexible should you use the gem Friendly Id. And again does Ryan comes to the rescue with another great RailsCast: http://railscasts.com/episodes/314-pretty-urls-with-friendlyid.
3. Change design
Ok well so this is just my opinion, feel free to ignore it. But their is some bad practices and signs in your examples, so let me just quickly go through what i think you should improve on.
Restful actions
You should, when possible always avoid creating controller actions that is not restful (simply put is the base actions index, show, new, create, edit, update and destroy the only restful actions). In your example does this mean that the product action of the posts controller should be changed to something restful. Why not move it to the product model controller and call it "show"?
Deeply nested resources
You should avoid nesting your routes to deeply. Is it really important to show both the category, the sub category, the product AND the model in your url? Maybe that's how your models are associated internally in your application but why should the user know this? If you don't have a list of subcategories at "/posts/product" and a list of products at "posts/product/41" is there no reason to have so long a route. A rule of thumb is "nest no deeper then two levels", ie. ":category/:sub_category". Further more does short routes mean better SEO.
As i said, feel free to ignore these suggestions, your application would work without these changes. However changing these things would greatly help you structure you code, and keep your codebase clean and maintainable. These rules and principles is not something i have just conjured out of nothing, but very accepted principles in the Rails community. You can google each of these principles or patterns and see a lot of articles and posts on why it's a good idea to follow them, especially when you work with Rails.
Resources
Rails Routing from the Outside In — Ruby on Rails Guides
norman/friendly_id - Github
#314 Pretty URLs with FriendlyId - RailsCasts
#63 Model Name in URL (revised) - RailsCasts
Take a look at the friendly-id gem
There's a great RailsCast about it
Add this to your model inmodel.rb
def to_param
name
end
and then add
#model = Model.find_by_name(params[:id]) to your show method, then you can get the url as you mentioned above.
PS: You Should have name field for Model table in your schema.
I think you are looking for nested routes. Please refer this link http://guides.rubyonrails.org/routing.html#nested-resources
and use to_param method in the model if you want to display model_name instead of id as explained by #Ajay Kumar
def to_param
name
end
where name is the model attribute for that specific model.
Why not a namespace?
namespace :posts do
resources :products
end
This should do I think..
Namespace does not include restful ids into the scope..
I have a CRUD resource defined in my routes.rb file: resource :user.
I'm adding a new controller method for the user called search_places, which is performed on the user to find other users with the same places. I'm adding a route it.
Right now, I have:
post '/user/search_place', which isn't very DRY. I'm new to Rails and I was reading the Rails routing documentation and figured that I could possibly use
resource :user do
collection do
post 'search_place'
end
end
Is this considered good practice? I know this works (it passes my rspec route test), but is that how its best done?
Thank you,
When you add second don't need of first.
Add this:
resources :user do
collection do
post 'search_place'
end
end
Remove this:
resources :user
That makes DRY :)
Suggestion: Resources name should be defined in plural if u follow rails convention. (i.e) resources :users
I have a Rails 3.2.8 model that is in a namespace. I'm sure it used to be that the namespace was automatically expanded out into what the table name would look like. e.g. Module::Model would become module_model in the database.
For some reason I have a problem now that this does not happen through the rails application. The migrations, models and controllers all live in a namespace but when the model looks for a table it ignores the table prefix and complains that it cannot find the database.
Here is the example
module Magazine
def self.table_name_prefix
'magazine_'
end
end
module Magazine
class Paper < ActiveRecord::Base
#some stuff here
end
end
When I do a query on Magazine::Paper it looks for the table "paper" and not "maganzine_paper" which it should. This is causing the whole application to exibit some weird behaviour. I have also tried setting the table name manually in the model with self.table_name but this only lets the model find the right table. Routes still play games with me as when I nest something below papers for example comments then it looks for a route that does not exist.
This is what is inside the routes. Comments should go to /magazine/papers/1/comments but it looks for a route called /magazine/comments
namespace :magazine do
resources :papers do
resources :comments
end
end
What is going on?
Update:
Ok so I figured it out but not sure if I should ignore it or see whats causing it. The engine name is magazine and in the engine I create a namespace for models called magazine but this causes the problems. So rails can't have a namespace name similar to the engine name?
I ran into the same problem, forgot my application's name (main module) had the same name as a namespace for my models. Changing either, the module name or the application name solves this issue.
If you just write
namespace :magazine do
resources :papers do
resources :comments
end
end
and run rake routes you can see it is looking for proper urls and when you say it is looking for /magazine/comments then you surely must have written another routes somewhere in the file.
When you write
module Magazine
def self.table_name_prefix
'magazine_'
end
end
And when you write your model with the same module name Magazine then you are replacing the same module with different contents within it. Instead of writing model Paper within Magazine module just include the module within the model Paper in following way.
class Paper < ActiveRecord::Base
include Magazine
#some stuff here
end
This will ensure your table_name_prefix method to be called when your model is loaded when your application starts.