beginner at Rails here.
Can you please help me wrap my head around the theory behind the very, tippy, top portion of most code samples that I see? 'The ActiveRecord::Base', 'Application Controller', & 'ActionController::Base' portions?
What would you call these three? Are they all objects? Classes?
I understand 'class X < ActiveRecord::Base' is to create an object in the Model, & that 'class ApplicationController < ActionController::Base' to create an object in the Controller... so is there something similar for creating an object in the View, just to round it off on all three components of MVC?
ActiveRecord::Base, ApplicationController and ActionController::Base are all classes. You would need to create an instance one of those to get an object, but you'll never do that. Instead you'll extend them to create new subclasses then create instances of those.
I believe there is a base class for views, but you should never see it under normal usage. Typically you'll be creating view templates rather than view classes, so you won't be dealing with Ruby classes in that section of the framework.
To add to what's already been said, as it's all accurate.
I understand 'class X < ActiveRecord::Base' is to create an object in the Model, & that 'class ApplicationController < ActionController::Base' to create an object in the Controller... so is there something similar for creating an object in the View, just to round it off on all three components of MVC?
This is down the right path, but there are some semantic differences.
class User < ActiveRecord::Base merely creates a subclass of ActiveRecord::Base. Until you do something like User.create() do you get an instance of that class, which may sometimes be referred to as an object.
A subclass is a special word for a class that has a parent. In ruby, you may remember classes are, quite confusingly, all subclasses of the Object class.
Also, subclassing ActiveRecord::Base shouldn't be thought of as creating an object in the Model. Instead, consider your subclass as a description of a model (which is generally some data that you wish to store). Every subclass is a model itself. It's all semantics, but it may help your understanding.
The same goes with the controller. You're not creating an object in the controller, instead you're creating a brand new description of a controller. That description isn't really concrete until it gets instantiated, which with rails happens automagically when you or a user request a page from the application.
Finally, there is indeed a class to round out the trio called ActionView::Base. Rails creates it automatically with a call to render in your controller.
ActiveRecord::Base ,ActionController::Base ,are the MVC based classes. However, you can create model or controller without extending those classes, then they will not having the features that provided by the classes.
however,in the view, commonly, there is no one to create object or model in the view. This can ensure to increase the readability and maintainability of your code. It will show more clean code. Besides, in the particular View like index.rb , it is actually connected with the controller,which you able to get the object instance that you initialize in the controller and use it to display your data in the view.
Related
I'm new on rails and I want to implement this diagram in Rails. The problem is with the heritage between classes, I don't know how to do that with models/controllers. Anyone have any idea?
Rails let your share features pretty easily among your models via 2 main pattern :
STI (single table inheritence) : basically just add a type string column and inherit your model class from its parent instead of inheriting from ActiveRecord::Base
Concern : Share some features grouped into a module you defined and include it into your target model or controller's classes
On your controller side you can directly build your own inheritence chain (making sure the first ancestor is your ApplicationController), use the concern pattern or other types of goodies such as Service Objects (and much much much more;-) )
I have functions that return true/false for user permissions (basically a wrapper for certain session variables). I would like the functions available to build menus in the view layer as well within the controllers. Is there any drawbacks in doing this? (Example below)
module SecurityPermissions
extend ActiveSupport::Concern
def has_this_permissions
end
end
class ApplicationController < ActionController::Base
include SecurityPermissions
helper SecurityPermissions
end
Although it is tempting to add everything in the view layer and the controller, it is still recommended that you don't do this. The idea is that the view should not concern about the logic. As much as possible, the view should only render something. Using decorators or page objects will help you abstract these out of your view context.
As for the controller, taking out "action" logic to a service would be my favourite way of simplifying everything. Controllers should not concern about how a model should be updated but it should now what to update.
I understand and appreciate that by putting # in front of a variable name in a Controller that it becomes available in whatever View is loaded. This is wonderfully useful, but I would like to understand the magic. How does it happen, and can it be stopped?
I am trying to DRY my CRUDdy resource controllers using inheritance, placing most of the logic in ApplicationController. The superclass should refer to the abstract variables #resource (for a single resource), #resources (for a collection of resources), and #parent_resource (for the parent resource when #resource is nested), but ideally the view would get more concrete names, for example;#customer, #customers, and #sales_territory respectively. Can this be done without sending duplicates of all objects (once in the abstract name, and once in the concrete name) to the view?
As I write this, the possibilities that come to mind are;
protected instance variables...does Ruby have such a thing, and
if so does the Controller magic hand them to the View?
setting the generic named variables to nil before render/redirect
using a protected empty method defined in the subclass to instead of
abstract named instance variables
What is the right choice in how to implement this?
What I'm assuming is happening here, is that there's a bunch of controllers in your app that literally just do the same thing and so you are wanting to make use of inheritance to DRY it up.
That being said, I'm not entirely sure the ApplicationController is the right place to dump all of this functionality as in the future if you had new controllers, they would also inherit all of this functionality without necessarily needing it.
I would do something like this:
Assuming you have controllers like this:
lions_controller.rb
tigers_controller.rb
hippos_controller.rb
and they pretty much have similar functionality... I would create a "Base" controller and then setup inheritance on child controllers. I would then also make an action that sets the "logical" defaults of child controllers, something like this.
AnimalsController.rb
class AnimalsController < ApplicationController
class_attribute :resource_class, :parent_resource_class
protected
def self.set_resource_attributes(options={})
self.resource_class = options[:resource_class]
self.parent_resource_class = options[:parent_resource_class]
end
end
LionsController.rb
class LionsController < AnimalsController
#call methods in AnimalsController here, start with setting the resource name
set_resource_attributes :resource_class => Lion, :parent_resource_class => Animal
end
and so on and so forth... the other thing that may be useful is to make use of the methods "instance_variable_set" so that you can set instance variable names in the view that actually make sense... You can make use of the class variables you just set to do this... so for example, lets re-open the AnimalsController.rb class:
class AnimalsController < ApplicationController
def show
instance_variable_set("##{self.resource_class.name.underscore}".to_sym, self.resource_class.find(params[:id]))
#... all the regular show stuff
end
end
This way, when you go to the lions#show path, what you will get in your view is access to a variable named #lion which will be set and contain an instance of the Lion class found through ActiveRecord.
Of course this pseudo code I threw in here can be cleaned up and DRY'd a bit more, but hopefully you get where I'm going with it. Hopefully this helps.
I have a GridDataController class that handles all of my data requests from my jqGrids.
I think my application would be easier to maintain if I busted that class apart, put the relevent actions in their respective controllers, keep the grid specific functions in a base controller class and then inherit from that class when I need to retrieve grid data in my controllers.
It doesn't seem right for the Base Controller class to reside in the Controllers folder as I do not want any of it's actions to be called.
Is there a convention for this?
No conventions. It would be easier for everybody though if you put it under Controllers, since its a controller, want it or not :). However, you can put it anywhere and refer to it inside your controllers by using and by inheriting from it (if that's what you want to do).
If you don't want its actions to be called, declare it appropriately as abstract class ...
So, no right answer to your question, but before putting it anywhere, thing twice and change your mind and put it back into Controllers :)
I've been told that the helpers are just for functions that are needed by the views.
Where should I put in functions that are used commonly by models? What about controllers?
What's the convention to place commonly used functions that will be used in:
1) models
2) views
3) controllers
Problem: Creating a module in lib to hold the functions and including the module in a class would create a boat-load of instance methods for the class.
Problem: What about functions that are common and needed in all three?
Problem: Creating a module in lib to hold the functions and including the module in a class would create a boat-load of instance methods for the class.
First organize, then optimize
Problem: What about functions that are common and needed in all three?
Do you really have methods that are needed in all the three and not exist yet ?
If yes, may be you can give an exemple
I think the question should be where to put logic in general.
You should first think what your method does before to think about where to put it.
But whatever you create, when it's getting big and or valuable, you should really think about exporting it as a gem/plugin.
Inner navigation logic (what to display and where to go after an action) : Controllers
App navigation logic; application_controller
Sub set of app logic; create a namespace with master controller, class API_controller < application_controller
Data logic (How to manipulate, process data) : Models
Data; Model class method (search, sorting, counting, macro process ...)
Datum; Model instance method (modification, micro process ...)
Data presentation logic (How to display data) : Helper, Partial and Decorators
Helper are not designed for that in my opinion.
Partial handle layouting of specific data.
application decorator; handle generic data presentation help
scope_decoration; you can use inheritance
Layout language logic (layout language help) : Helper
Specific to your app; application_helper
Specific to a model ...; model_helper, but you should consider decorator
Generic; export it in a gem (super form helper, templating system ...)
Layout logic (should i display this menu ?) : ?
Helper/decorator/model can should answer the question : #user.can_edit?(#article)
Layout handle the display <%= render :partial => allowed ? "something" : "somthing else" %>
I think if you are not in this configuration you are creating kind of backend system.
So it should go in lib, then in a gem later.
This organization is just an exemple. The most important thing is to organize your code and split different logic layers and don't hesitate to refactor/export code to make it generic after adding new features...
for Controllers - put common methods in application_controller.rb
for Views - put common methods in application_helper.rb
for Models - monkeypatch ActiveRecord::Base to include common methods OR write a module with common model methods and include it in the models that need it OR do it in OOP way by subclassing ActiveRecord::Base with your abstract class, then inheriting all your models from this class.
To use common methods in both Model and Controller, do one of the following:
Write a plain ruby class, put it in /lib or elsewhere, just make sure it's loaded, then require it when you need to use its methods.
Extract common functionality to a gem, install it, require it when you need it. Publish it to rubygems if it's something valuable.
... Usually, I put those kind of functions into common superclasses: For models, that could be (for example) Animal for subclasses Dog, Cat, etc. Within the Animal model, you would have to
self.abstract_class = true
so it doesn't expect a table for that class. For controllers, you could either use ApplicationController or you could make your controllers be derived by another common subclass.
In the Model you should store all the methods that have a relation to the model itself like manipulating attributes, scopes, associating,...
In the View you dont store any logic! The logic belongs to the model. In the view you only put code that helps you to display stuff.
The Controller is the "bridge" between both. You select data in the controller, call methods that are stored in the model,... A common failure is to store the logic in the controller which should be stored in the model.
When you store a method in your Modelyou can access it from the model, the view and the controller! If you have a method that doesn't have a relation to a specific model or its needed in several models you can use the Helper. An example for such a case might be a method that rewrites your url using a pattern. This might be needed in 20 models to prepare a string for to_param. That method would be stored in an Helper that could be included in the Models its needed.