Are rails helpers the same as methods. Aren't they just custom to the views?
I know that methods can be made within the controllers but the way I have been understanding that helpers are custom made methods that can be called upon and used within the views.
Helpers are functions defined in the helpers directory, and they are different from the controller actions.
Let's say, you are creating a form in a view, and you want this form to have a drop down menu to all countries in the world, then you would define a helper inside helpers directory that contains all the countries and then call this helper inside your view, instead of listing the actual countries in your view.
Controller actions on the other hand are different, they are also functions like helpers, but they perform operations like create a new record in the database, or delete a record, and so on.
Read through http://guides.rubyonrails.org/action_controller_overview.html for a deeper understanding.
Related
I'm trying to better understand the Rails workflow, specifically RCAV in relation to MVC. I know that MVC is the typical structure of a Rails app and that RCAV is the standard order of building various components of the app, however, I'm a little confused about the correlation between the two.
For example, I'm assuming the routes in RCAV are what link the models with views and controller in MVC. Is this correct?
I'm also guessing that the controller and view in RCAV are the same as the controller and view in MVC and simply represent the order in which you build them. Is this correct as well?
What I'm really stuck on is the Action part of RCAV - does this represent the Model component of MVC?
Sorry if my question doesn't make sense, just trying to get a better hang of the standard Rails workflow and the order in which various components of an app are typically built. I wish it were a little more distilled i.e. "first build Model, then Views, then Controller" but this whole separate RCAV thing is confusing me a little.
To your title question, no.
To elaborate, it's kind of confusing to map out RCAV (the sequence) against MVC (the framework), but I'll see if I can clarify. It's worth noting that the concepts themselves are not as complex as they seem, it's just confusing to explain.
RCAV
(Route-Controller-Action-View)
Routes are defined in config/routes.rb. You may think of them as the coupling between an HTTP Request and a Method (a specific type of method called an Action). On the one side it defines a path (ex. "/login") and one of the HTTP verbs (ex. "GET"), and says that whenever that type of request is made to that location, to perform the appropriate action. On the other side, an action is given in the form of the name of its controller (ex. "sessions"), and the name of the method itself (ex. "new").
Controllers receive the request according to the routes (so following the above example, if a user navigated to www.example.com/login, they would wind up in the sessions controller, which would be housed in app/controllers/sessions_controller.rb). The Controller may perform a number of functions prior to (and following) the action, in the form of callbacks. Callbacks are arguably a more advanced concept than what you need to understand right now, they are an important step (and the reason I explain RCAV as "Route >> Controller >> Action >> View", not as "Route >> Controller-Action >> View").
Actions are public methods in the Controller. Again, by our above example, you'll be hitting a method named "new" in the sessions_controller when a user navigates to www.example.com/login. Actions may perform any variety of functions, and there is often interaction with the model here (for instance, you may have a session model in app/models/sessions.rb with a method named "logout", and perhaps the first thing you do when you hit the login page is ensure the user is currently logged out by calling Session.logout. This is a poor design, but a decent example). Your action must "return" in one way or another. Assuming your action is meant to be consumed by a user directly through their browser (as opposed to as, say, a JSON or XML service), you will either render a view now, or redirect_to another action.
Views are, dare I say, the "end result" of the action. If nothing is specified, the above example will end by rendering "app/views/sessions/new.html.erb" for the user (Rails defaults to rendering the view whose path matches the controller and action, but as referenced above you could name something different). In this file you will also potentially make reference to the model associated with sessions (but this time inside of ERB tags, to be compiled into HTML).
MVC
(Model-View-Controller)
Models are classes tied, generally, to tables in a database. They contain validations for their fields, class methods, and instance methods. Say your database keeps track of sessions. Then you could potentially grab a list of sessions by calling Session.all anywhere in your application. You'd probably use an action in the Sessions controller to save this list to an instance variable (maybe #sessions), which could in turn be accessed in its appropriate view (<% #sessions.each do |s| %> ... <% end %>).
Views are essentially the web pages. They can bring along their own styles and scripts, and exist in the form of HTML files with embedded ruby. They are the end point of request made to your site (unless you're hitting a service which returns something like JSON or XML instead).
Controllers contain all the actions a user may access, often prepare variables via methods from the models, and generally drop the user into a view.
In Summation
A user accesses a route. The route drops them into a specific action within a controller. The controller (in the form of callbacks) and the action (on its own) prepare data from the model (via instance variables) to be consumed by the view. The view is then rendered into the users browser.
This is a simplification, but in the most standard cases, this is how the MVC framework (and rails, specifically) functions.
I read in this blog that helper methods should not interact with the database directly or manipulate data for views. These tasks should be handled by decorators.
If this is the case, why do we typically put the #current_user methods in helper modules? (In Rails)
I will cite recap from coderwall.com
Helpers
Helpers are generic methods which can be use for different kind of objects. I create this kind of helpers link_to_update, big_image, styled_form, etc. Those methods create an html code with a css style or a standard text for example.
Partials
Partials are used to split a big view into smaller logic parts and for larger html code. I can have a partial side_menu, comment_list, header, etc.
Presenters
Presenters is for more complicated queries with two or more models. I have some partials like #page_presenter.page_in_category(ruby_category) or #user_presenter.user_following(an_article).
Decorators
Decorators should act with only one model and shouldn't take parameters (if it's possible). I can do something like this user.full_name, page.big_title or category.permalink. I use the gem Draper.
So, essentially decorators are things which take data from single model object and manipulate it in some way (for example, squishing first_name + last_name into full_name and such things).
current_user, on the other hand, definitely doesn't belong to the decorators because it doesn't deal with manipulating any object's data – it actually finds the object you need (using session/cookies data for that).
I'd say its place is in ApplicationController (or one of its specific descendants which you can build, say, AuthenticatedController or such), because you often need to know current_user in a controller itself (not its view), and it takes unneeded efforts to make your view helper method available for controller.
Every show action in my app has the same template for every model (it is an Admin-portal type interface). I have a view show.html.erb that all of these models inherit.
The controllers all use InheritedResources, so I have access to some helper variables such as resource, which I use to display the attributes for the model being shown through resource.attributes in my parent view.
What I would like to be able to do is whitelist which attributes are being shown in each model. I have thought of two ways to do this... the first is to define some method in a class my model's inherit from, say it is called attr_visible and define each attribute in the model. The reason I don't like this approach is that it puts too much of the view logic in the models. I would rather provide my views with the model, and let the view determine what is displayed.
The second approach is what this question is about. I want to have a file /app/views/users/show.html.erb, and set which attributes for a User I would like to be shown, say something like:
#attributes = [:name, :email, :etc]
And then pass them to the parent view which I described in the beginning of this question. That view would then be able to loop through #attributes and display the attributes necessary.
Is it possible to use a "super"-type method from views? Everything I have read about view inheritance suggests the view is loaded based on where it is located in the directory structure, and then after that you're out of luck.
edit: I have sort of done what I want. I defined a partial _show.html.erb in the /app/views/users directory that looks like:
<% #attributes = ['name', ...] %>
And then in the parent view I call <%= render "show" %> before looping through #attributes. This works, but feels clunky since I am not actually rendering anything when I call render. Is there a better way?
You can use a presenter for this. Adding "view" logic to a model is better done through this type of object. Take a look at draper.
Once the resource is decorated, you can just call visible_attributes or whatever. Of course, you would need to implement that method for each resource.
Views inheritance works when looking for a view, not when rendering it. Take a look at the original plugin implementation.
Other way would be to make the show parent view to call render on resource and create several partials for the classes.
For a better understanding on Rails Views, I recommend The Rails View: Create a Beautiful and Maintainable User Experience
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).
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.