Rails convention - ruby-on-rails

I'm really new to Rails (for coldfusion) and before I even start coding I want to make sure I understand the convention and apply it right.
One of my concern is the following situation using Rails convention:
I create a table called users
I create a model called User.cfc
I create a controller called Users.cfc
create a register page so I will add a method called register in the controller Users.cfc since its specifically related to the model User.
But now lets say I create a method that call multiple model then where should I put that method?
Example:
I'll take facebook wall post for this example. For each of my post many comments can be added. So I could create a method name postMessage so in that method I would call the model "Post" and also the model "Postcomment" so my question is should I put the method postMessage in the Controller "Posts" or "Postcomments"?

That really depends on the purpose of the method. If it's a user who's looking at his collection of Widgets, you might create a "widgets" method in the Users controller.
On the other hand, if you want to list all the users who bid on Widget #32, then you might add a "users" method to the Widgets controller.
There is no definite rule with these types of things. While you generally want a 1-to-1 correlation between Models and Controllers in Rails, there are exceptions. You may have some Models without their own Controllers (e.g. Login, EmailAddress), and some Controllers with no associated models (e.g. Home, Admin).

Related

Does a controller extend from a model in Rails?

Been working on Rails for a bit I can't get my head wrapped around how there is almost nothing written in a model.rb file when just creating a basic CRUD application.
I was looking at a controller.rb file and was wondering why the controller file has access to model methods like all and create when there seems to be no connection between the two files.
Should't the model object methods like modelname.all and modelname.create etc. be written in the model file instead of the controller file?
TL;DR
No, it doesn't.
General Answer
A controller does not have access to model methods as you think, in the controller you never just write all or create, you write something like User.all or #user.create. You are calling the methods on the model class or instance. You are simply using the model in the controller, but this is not limited to the controller, you could do exactly the same thing in the views if you really wanted to, or you could create custom service objects, or policy objects, or repository objects, and you could still call User.all etc from inside them too.
For a very basic application you are correct you can get by writing very little or no logic, but this is only because Rails provides us with methods and does it all for us (hooray!).
Nothing in a model file just means nothing specific to this particular model... inheriting from ApplicationRecord or ActiveRecord::Base means you have built in all the class methods (all, where, find, find_by, etc) and all the instance methods (new, create, update_attributes, etc) pre-defined for the model.
The controller determines what needs to happen, the model has the methods to make it happen, so
def index
#model = Model.all
end
Means that at the point of displaying a list of all model records, you access the model's class method all

How can I keep my Rails controllers DRY and utilize my own API?

Let's say I have a controller called Books (and a corresponding Book model), and a controller called Users (and a corresponding User model). Each of these controllers has the standard CRUD actions, and they serve as the vehicle for my website's API as well.
Most of the pages on my site fit into this framework easily. For example, viewing a book. Or viewing your user account. Or editing your user account. Etc.
But let's say I have an index that will be somewhat unique: I want to show a list of users AND a list of books. This raises a few questions:
What controller should this go under: UsersController, BooksController, or a new controller?
If I create a new controller, is that considered a violation of any MVC principles since it won't be tied to any particular model in particular?
How would this new controller action retrieve the data? If I write new ActiveRecord queries inside if it, them I'm repeating myself, since I already have code like this in my other controllers. I'd also prefer to consume my own API, if possible.
You can use scopes(google search it) in your model to keep your controllers lean. Depending on what you want to show you can create a new method and view. lets say you have a user dashboard that list your books and the authors which are in seperate models.
you can create a new method called def dashboard inside your user controller since it relates to your user.
def dashboard
end
you would create a helper method in your model to scope the specific queries. Remember to also add the proper route to your routes file.
I hope this helps
Whichever you want.
1) I would probably write another controller, though it may end up to be a question of taste and it may change with the context of the application.
2) I would fetch the data from both models. There is no MVC rule mapping controllers and models one to one.
I am not quite sure what you mean by "queries" but you can put them in model methods (or scopes) to avoid DRY. Of course one gets tempted to do simple queries in controllers because ActiveRecord encaplulates them as methods (e.g. User.find(n) )

REST API naming convention issue

I have a controller that handles CRUD operations on quizzes, called QuizController.
Then, a user can go take the current quiz (there's only one available at a time).
It's tempting to name that controller QuizController as well, and I could if it were namespaced differently. But that isn't innately descriptive enough to me.
It could be called QuizResultsController. But that's not great either.
How would you name such a controller that displays the current quiz to a user and let's them submit their answers?
The controller that handles CRUD operations for your quizzes should, by convention, be called QuizzesController, freeing up QuizController for use in the context you've described.
That said, I'd go with QuizzesController and CurrentQuizController to make the distinction greater.
You could add a #current action on QuizzesController which shows the current quiz if you didn't want to create an entire single-purpose controller.

Best Practice: Where to place a function which is called from view

I am new to Ruby on Rails and the whole MVC style of doing things. This question isn't so much technical as it is conceptual. Say I have some function myFunction that I wish to have a user execute from the View by pushing a button. Should I have this function in thew Model, or the controller?
If the function relates clearly to a particular model e.g. "placing an Order", "authenticating a User" then place it on the appropriate model and add a small amount of controller code to create/retrieve the appropriate model and call the method.
If it doesn't obviously belong on one of your models then you may want to create a separate class or module for it, and again add a small amount of controller code.
Do some Googling for "skinny controllers and fat models", this is the approach generally favoured for Rails projects. e.g. see this (old, but still useful) post from Jamis Buck, or this more recent post.
It should goes to controller's method which is using models to do some business logic (not necessary connected with persistance). Probably, you should also read about RESTful apps and routing (there is a lot of guides about it).
Controller's are just expected to have the Input and Output which is the request parameters and the response/redirect. So according to you if a user clicks a button and myFunction should come into picture. Put the call to myFunction inside the view helper and the function myFunction inside the model. So your View is also clean from code and the Skinny controller and Fat models come into picture

Rails STI Controllers

I have a Rails site using STI with the following classes:
Pages
Homepage < Pages
LandingPage < Pages
On the front-end all requests get handled by the Pages controller. However, if the object detected is actually an instance of LandingPage, i'd like to have the action on a LandingPages controller get called. (for example, the show method in the child controller classes will pull in some specific lookups that aren't always relevant).
Any suggestions on how to best accomplish this?
Thanks
This sounds a bit like you are clouding the MVC distinction, but it should be doable.
I'd add a series of tests on the Pages model (e.g. supports_buzzbar_foo? or wiggums_itemization_controller, then override them as appropriate in the subclasses) and use these in the view to conditionally generate the appropriate links to the controller methods you want.
That way you're keeping each part (roughly) doing it's job.
Markus' solution should work. You could also keep your links in the views pointed to Pages, evaluate the incoming object and then redirect_to the appropriate controller based on the object class.
However, unless you're performing completely different actions with each type of object, then you'll wind up with duplicate code in your controllers. So you might be better off sticking with the Pages controller and just adding some methods that handle the extra lookups that are needed for that object.

Resources