What are drawbacks of naming controllers in singular form is Rails? - ruby-on-rails

I know in Rails we follow conventions. And we should name controllers in plural form.
Recently I hired a freelancer to help me with one part of my application in Rails as I'm really new to this framework and ruby.
I had a PortfolioController - this is just feels right because portfolio is a container for entries (who says "I have portfolios"?).
The freelancer said it's not right and I will have troubles not following the convention and renamed it to PortfoliosController. I asked several times what are the exact problems I will have if I name my controller PortfolioController rather than PortfoliosController and I didn't get any explanation other than "You will have problems".
So, can anybody tell me what those problems are?

Well, the simplest reason would be that anyone else who works on that project will probably refer to it in the plural while working on the code, then have to realize "oh, they decided to not follow convention in that one controller" after an unspecified time period of "WTF?" while they try to figure out what they are doing wrong. Also semantically, your controller is a controller of ALL the Portfolios in the Portfolio table.
Code-wise you will have issues with routes. You will have to craft a bunch of non-standard routes because http://my_app/portfolios goes to the index action of the controller by default. You then show a particular portfolio with http://my_app/portfolios/1 which will show you the portfolio with the id of 1. So be prepared to create and maintain a host of custom routes in your config/routes.rb file. You see similar problems with things that have names that are the same whether plural or singular like equipment where you can have one piece of equipment or many pieces of equipment. See this: rails link path and routing error when model singular and plural name are the same (e.g. equipment, species). Not only is it making your routes wonky, it is causing conflicts in methods like portfolio_path or portfolio_url.

Related

Why does naming convention of models differ from controllers, helpers, etc.?

I am trying to build a rack based web framework on my own, and I got confused when I refer to the design of Ruby on Rails.
Why should a model in Rails be named like User instead of UserModel, just like controllers or helpers do (for example, UsersController, PostsHelper)?
If the naming convention of model is good, why don't controllers or helpers follow the same rule? The Controller and Helper postfix is bit tedious.
Is it good to namespace everything? For example: Controller::User, Model::User.
Are there any good references/books that talk about the file structure of software?
I think that it's for convenience sake. You would never usually reference the controller and helper classes in your code, whereas you reference the model classes all the time. If they were called UserModel you would have lots of code like
user = UserModel.first
post = PostModel.first
there's two problems with this: it breaks the convention of "call the instance variable name after the class", which is a simple bit of self-documentation, and also it's cumbersome, with a lot of repeated information.
Also, the User class does actually represent a real life user, whereas the UserController class doesn't represent anything in the real world, it's just part of the machinery, if you know what i mean.
EDIT - some more answers:
3) Namespacing should be reserved for separate sections of your site, like an admin section for example: you can have an AdminController which inherits from ApplicationController, and adds a few more bits (such as a before_filter for checking that there's a current user and that they're an admin), and then your other admin section controllers inherit from AdminController. Namespacing in the routes allows easy management of this.
4) As for books, read this: http://www.amazon.co.uk/Agile-Development-Rails-Pragmatic-Programmers/dp/1937785564/ref=sr_1_1?s=books&ie=UTF8&qid=1450792683&sr=1-1&keywords=hansson+rails
It has some "Make a blog in 15 minutes" type stuff which i would actually recommend NOT diving into until you understand the underlying architecture, which is well explained elsewhere in the book. Too many people dive into Rails without understanding what they are doing (their hapless questions fill this forum).
All about convention, had to decide something. I don't speak for the rails core but this is my thoughts.
Model - In most cases, this is a representation of a single instance of a something. Although you could have cases where that is not the case, it helps me to conceptualize the singularity of it. I.e. I am dealing with a User not a Users
Controller/Helpers/Tablenames - In the database a User model maps to users table. The controller and helpers follow the same convention of the database.
Namespacing is good, but you should only namespace something when it makes sense on a clear boundary.
A great ruby framework to look at that is not rails is Lotus - http://lotusrb.org/ It uses namespaces heavily.

Steps to simply Change the Name of my Model

So I think I jacked up my naming conventions (or rather realized I want to do it a different way). I initially created a "Persons" model (which created person.rb). I also created a persons_controller, but apparently rails looks for "People" so I changed the controller name to people_controller.rb (in the files...not in the command line).
I'm new to rails so I really just need to scrap all this and change my names because this setup (having to using Person, Persons, People) throughout the model/controller/views is just a bit confusing for a beginner. All I want to do is change the "Persons" or "People" to the word "Players". So if I were starting from scratch I'd do "rails generate model Player" in the command line, and "rails generate controller Players". But I have no idea how to go about changing my existing controller and model names to this...and I couldn't fully understand some of the older questions related to this topic.
Any help would be greatly appreciated here. Step by Step instruction like your talking to a 12 year old is also highly encouraged given my novice status.
thanks guys,
The basic conventions that will explain everything
About class name and file name
Class name must correspond to file path. In English, if you have a Thing model, it must be in models/thing.rb file ; if you have a ThingsController it must be in controllers/things_controller.rb
Class name with camel case (i.e SomeThing) must be declared in a file with underscore (i.e some_thing.rb). The file name is written in small letters and underscore is used to "separate" the words. Other example: ThisIsEasyToUnderstand will give this_is_easy_to_understand
About model name, table name and controller name
A model name is singular, a table name is plural and a controller is plural. For example a Thing model will have a things table, and will work with a ThingsController controller
Rails try at most to use correct English syntax, so a Person model will work with a people table and a PeopleController controller
You may have trouble when the model name is, in English, the same in its singular and plural form. Ex: aircraft, eyeglasses, scissors etc.. I won't details the solution to keep my answer clear, but know it can append and you can find solutions on those a bit everywhere on internet.
As an overview:
When you create a model, create a name in its singular form
When you create a controller create a name in its plural form
if you need to rename models or controller you already created you must rename in your code but also rename the file name
If you need to rename a model you will also need to rename its table, and you need a migration for that (search google for "rails migration rename table" )
Hope it help for your first steps in Rails
You can quickly scrap a model (and its associated files) by calling
rails destroy model [modelname]
Same with controllers, scaffolds, etc.
rails destroy scaffold [modelname]
rails destroy controller [controllername]
Of course, there's no undoing this after you've deleted them, so I'd create the new controllers/models/scaffolds first, migrate any relevant code, and then destroy the useless files.

RoR: How to use routes to filter refinerycms backend content?

everyone. I'm new to refineryCMS( and rails also). I summed up my question in the end of this article in case the problem description is too long.
Here is my question:
How do I use routes( or namespace) to filter backend contents?
For example, I have several departments on my site. They have similar structures, yet the contents are different. I want to manage them separately. Say, I have department ABC and department EFG and department MAIN, I want to manage them through /refinery/ABC and /refinery/EFG and /refinery(/MAIN).
How can I achieve something like this?
Currently I've two ideas, but not knowing how to implement.
First, I may create each department as rails engine and then mount them on the main_app. However, I don't like this solution because it will duplicate many almost identical tables since each department's structure are quite similar. And I'm not familiar with creating engine, worrying about the performance.
Second way I've thought out is to make every Refinery::Pages, resource and custom engine model belongs to certain department. And then I could write a controller to filter all those thing out by specifying which department like I mentioned above "/refinery/:department".
In short, I prefer the second way, though I don't know how to:
make every model(custom engine or Refinery native ones) belongs to department. Especially for Refinery native ones(resource, image, pages)
how to duplicate the admin rendering like refinery's default backend after controller has filtered content I want.
After some search up, I found that there are too many #variables to filter properly. Is there some easier way?
Thanks in advance!
Routes.rb
try put the:
get 'refinery/:dep' => 'refinery#deps'
then in refinery controller your put
def deps
dep = params[:dep]
*some code*
end

Summary of Ruby on Rails fundamental concepts

Being new to Rails, I am having a difficult time finding a website or reference that gives a run down summary of Ruby on Rails. I understand MVC, ActiveRecord, and that sort of stuff on a basic level, but I am having a hard time understanding some of the relationships and fundamentals. For instance:
What are all naming conventions I need to be aware of?
How should controller actions be structured and named?
What are the best ways to render information in a view (via :content_for or render a partial) and what are ways I shouldn't use?
What should go into a helper and what shouldn't?
What are common pitfalls or something I need to do correctly from the very beginning?
How can you modularize code? Is that what the lib folder is for?
I have read a number of responses on StackOverflow in regards to this question, but all of them just point to a 300+ page book I need to read, whereas I just want a concise summary of what's important.
Some resources I am already aware of, but do not offer a concise summary of fundamental concepts for new users:
http://railscasts.com/ (good, but fragmented)
http://guides.rubyonrails.org/ (assumes you already understand relationships between everything)
http://ruby.railstutorial.org/ (paint by colors, no good summary)
Rails AntiPatterns (great, but you have to read the whole thing before you understand anything)
The Rails 3 Way (great, but again, you have to read the whole thing before you understand anything)
Thank you for any help, references, or guidance you can provide!
P.S. I would like this wiki to become a living document, so please add to it, edit it, etc. as you feel necessary.
1. What are all naming conventions I need to be aware of?
db table is plural, model is singular, controller is plural. so you have the User model that is backed by the users table, and visible through the UsersController.
files should be named as the wide_cased version of the class name. so the FooBar class needs to be in a file called foo_bar.rb. If you are namespacing with modules, the namespaces need to be represented by folders. so if we are talking about Foo::Bar class, it should be in foo/bar.rb.
2. How should controller actions be structured and named?
controller actions should be RESTful. That means that you should think of your controllers as exposing a resource, not as just enabling RPCs. Rails has a concept of member actions vs collection actions for resources. A member action is something that operates on a specific instance, for example /users/1/edit would be an edit member action for users. A collection action is something that operates on all the resources. So /users/search?name=foo would be a collection action.
The tutorials above describe how to actually implement these ideas in your routes file.
3. What are the best ways to render information in a view (via :content_for or render a partial) and what are ways I shouldn't use?
content_for should be used when you want to be able to append html from an inner template to an outer template -- for example, being able to append something from your view template into your layout template. A good example would be to add a page specific javascript.
# app/views/layout/application.rb
<html>
<head>
<%= yield :head %>
...
# app/views/foobars/index.html.erb
<% content_for :head do %>
<script type='text/javascript'>
alert('zomg content_for!');
</script>
<% end %>
partials are either for breaking up large files, or for rendering the same bit of information multiple times. For example
<table>
<%= render :partial => 'foo_row', :collection => #foobars %>
</table>
# _foo_row.html.erb
<tr>
<td>
<%= foobar.name %>
</td>
</tr>
4.What should go into a helper and what shouldn't?
your templates should only have basic branching logic in them. If you need to do anything more intense, it should be in a helper. local variables in views are an abomination against all that is good and right in the world, so that is a great sign that you should make a helper.
Another reason is just pure code reuse. If you are doing the same thing with only slight variation over and over again, pull it into a helper (if it is the exact same thing, it should be in a partial).
5. What are common pitfalls or something I need to do correctly from the very beginning?
partials should never refer directly to instance (#) variables, since it will prevent re-use down the line. always pass data in via the :locals => { :var_name => value } param to the render function.
Keep logic out of your views that is not directly related to rendering your views. If you have the option to do something in the view, and do it somewhere else, 9 times out of 10 doing it somewhere else is the better option.
We have a mantra in rails that is "fat models, skinny controllers". One reason is that models are object oriented, controllers are inherantly procedural. Another is that models can cross controllers, but controllers cant cross models. A third is that models are more testable. Its just a good idea.
6. How can you modularize code? Is that what the lib folder is for?
the lib folder is for code that crosses the concerns of models (i.e. something that isn't a model, but will be used by multiple models). When you need to put something in there, you will know, because you wont be able to figure out what model to put it in. Until that happens, you can just ignore lib.
Something to keep in mind is that as of rails 3, lib is not on the autoload path, meaning that you need to require anything you put in there (or add it back in)
A way to automatically require all modules in the lib directory:
#config/initializers/requires.rb
Dir[File.join(Rails.root, 'lib', '*.rb')].each do |f|
require f
end
I wrote some naming conventions some time ago:
Rails conventions
General
All filenames are in snake_case following the same conventions
- Model: singular (e.g. Restaurant)
- Controller: plural (e.g. RestaurantsController)
- Table in DB: plural (e.g. restaurants)
- URL's: all in plural (e.g. /restaurants, /restaurants/:id, /restaurants/new)
rails generate Commands
Create model: singular (because the name of the model is singular). e.g. rails g model Restaurant name:string rating:integer
Create migration: plural (because we use the name of the table). e.g. rails g migration AddDescriptionToRestaurants description:text
Create controller: plural e.g. rails g controller Restaurants index show
Model (singular)
ActiveRecord methods
All in singular, because all ActiveRecord's methods are linked to the model.
Examples:
- Restaurant.all
- Restaurant.create(name: "Burger King", rating: 2)
- Restaurant.find(params[:id])
Associations
Singular in the belongs_to. Because it belongs to one element.
Plural in the has_many. Because it has many elements.
e.g.
class Restaurant < ActiveRecord::Base
has_many :reviews
end
class Review < ActiveRecord::Base
belongs_to :restaurant
end
Routes
Resources
Plural when defining a route for a resource:
resources :restaurants
Route helpers
index: plural (because we are showing a list of elements). e.g. restaurants_path. Can also be used used for create.
show: singular (we are showing just one element, it needs the element inside parenthesis). e.g. restaurant_path(#restaurant). Can also be used for update & delete.
new: singular. e.g. new_restaurant_path

What kind of information can the Model access in Rails?

In Ryan Bates's first episode on complex forms, he adds the following to a model:
# models/project.rb
has_many :tasks
def task_attributes=(task_attributes)
task_attributes.each do |attributes|
tasks.build(attributes)
end
end
I've never thought about this before, but how does the Project model know what "tasks" of which Project instance? Does that come from the has_many association? Is it like, when the project is running and I'm viewing a Project, that's the "active" object so project.rb knows which Project object we're referring to, so it knows that tasks is really some_current_project.tasks? (I'm obviously grasping at straws here.)
Also, if someone would point me to some reference that explains other questions like this one, I'd really appreciate it.
I hope my question is clear. Please ask for more clarification in comments if needed.
Please note: I know that Active Record handles CRUD actions and that objects correspond to rows in tables, etc. Those are just descriptions of what Active Record is. I'm looking for how it works when the project is running. I also now the constructs MVC, but I can't seem to find a detailed explanation of what information is sent where with respect to Rails.
(Not sure I fully understood your question, feel free to let me know if that's the case.)
A rails model is basically a ruby class that is persisted to a database. So it acts like a normal ruby object for the most part, with some database magic mixed in.
You tell rails which project instance to load (e.g. by providing an id), and it loads the data from the database.
Then, when you call project.tasks is when the magic happens: the Project model has no tasks method, so it will trigger ruby's method_missing method. This will then load the associated records into model instances and provide access to them via a rails object.
Since a project has many tasks, rails knows it should look into the tasks database and load the rows where project_id is equal to the project model's id attribute.
In short, ruby meta-programming and monkey patching possibilities make much of rails' magic possible.
(Edit for question on routing.)
When you want to edit project number 13, you go to a URL that looks something like www.mysite.com/projects/13/edit. If you look at routes.rb in your config directory, you'll see (in Rails3) resources :projects what Rails does is set up all sorts of paths for you. Behind the magic, the edit path looks like
get '/projects/:id/edit' => 'projects#edit'
This basically says "when a user wants to see www.mysite.com/projects/13/edit, send him to the edit action in the projects controller and set the id parameter to the value that's in that place.
Then in your controller, you'll load the appropriate project with
#project = Project.find(params[:id])
In a similar way, you could do this (this is an dumb example):
In routes.rb, put
get '/projects/:id/edit_name/:name' => 'projects#edit'
And then in you controller
#project = Project.find(params[:id])
#project.name = params[:name]
So rails basically uses magic to assign values in the URL to params you can work with in your controller. You can read more about routing here: http://guides.rubyonrails.org/routing.html

Resources