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
Related
I have a functionality that doesn't relate to incoming requests (like get,post,etc).
But I want to follow MVC convention and make it like Model-Controller:
in controller part I will process income requests from another parts, decide from which model it should retrieve information, authorization, filtering and so on;
in model part I will store information, validate it, expire it and etc.
In Rails the controller's actions can be called by income request directed by routes file.
The problem for me that if I've created a controller like this:
class SomeController < ApplicationController
def some_action; end
end
How can I call method some_action from SomeController from any place in my application?
P.S. Calling SomeController.new.some_action doesn't seem right to me, because I think all controllers are parts of app object.
You can do this by instanciating the controller.
SomeController.new.some_action
However this is not really an MVC way. I don't really know what you want to use it for, but probably there is a better way. For example it can be done as in the model, as the modification of data should belong there not to a controller.
I think you should probably create a PORO which will encapsulate this functionality in some method. So that any logic dependent functionality should be within that instead of in the controller. Then you can call them in either controller.
I am developing a rails app and I want all my objects to have a certain method that process them. Now, while I realize that I could write that method in each object's model, I would rather stick with the DRY (don't repeat yourself) theory and place the method in one place.
Is there a place I could place a method where all my objects have access to?
Ruby and rails offer a number of options depending on what object you want to have access to a method.
ChiuBaka's answer is one option, however rails in particular offers a number of more readable options.
If you are looking for something on the controller/view level. You can simply place it in the app/helpers/application_helper.rb file. If you want to limit access you can create controller specific helper files in the same directory.
If you are looking at models. You can simply create a base model that inherits from activerecord::base, implement your method there, and then have your models inherit from that.
class MyBase < ActiveModel::Base
def myinstancemethod
end
def myclassmethod
end
end
then
class MyModel < MyBase
end
then you can call like so
instance = MyModel.new
instance.myinstancemethod
or
MyModel.myclassmethod
Place the code you want in all of your models in a module in your /lib folder and require it in your models.
I understand that it is best practice to refactor as much of my code as possible into the models, however I am relatively new to rails, and programming as a whole. One of the concepts that seems to be causing me a little trouble is the nature of models, and understanding the scope or the availability of methods and variables.
First of all with a typical method written in the model what are the limitations (scope) that your method can be called on? How does the .self aspect work? What controllers / views have access to methods defined in the model?
I understand that these are rather basic principles but I believe that my “assumptions” with regard to this are causing me all manner of problems.
In Model-View-Controller (MVC):
A model holds your data, and any functionality closely related to your data (low level logic)
A controller holds your business logic (high level application logic)
A view holds your presentation layer (user interface)
Views have access to any public model methods. (Note: all ruby methods are public by default.) Of course, the model object must be instantiated first in the appropriate controller method, and must be instance variables (i.e. #person) and not local variables (i.e. person) in the controller.
Controllers also have access to any public model methods.
Protected methods limit access to within the class or within any of its children. Private methods limit access to within the class, only.
It appears to me that class methods, i.e. def Person.some_method ..., are visible anywhere whether or not they are defined as public, protected, or private, although this is counter-intuitive.
Regarding your question about self... You can use self for all calls to the model's own methods from inside that model, and you won't go wrong.
e.g. for Person model having first_name and last_name columns:
class Person < ActiveRecord::Base
def full_name
"#{self.first_name} #{self.last_name}"
end
def parse_name full
self.first_name, self.last_name = full.split
end
end
However, that's overkill. You actually don't need to use self for retrieving attributes in ActiveRecord, only for setting attributes, so the following is fine:
class Person < ActiveRecord::Base
def full_name
"#{first_name} #{last_name}"
end
def parse_name full
self.first_name, self.last_name = full.split
end
end
Based on your questions, it would appear you need to read up on Object-Oriented Programming and the MVC pattern. These are not exclusive to Rails, of course.
In short, there is no real limitation in what you can use to access the Model.
Technically you can call methods from your models in your views and your controllers, or other models.
Here's how I look at it:
Models = Your application's logic
Views = Front-end for your models, tying in the pieces that you want the user (or service) to see
Controllers = Glue for Views and Models, calls model data and hands it to the view
You should shy away from calling your models directly from your view.
If you are performing more than 1 or 2 operations on an object in your controller you should probably move it into a model method.
From here, I'd reccomend you picking up a book to learn about what classes do, instance methods, class methods, etc.
I recommend "Learn to Program" from Pragmatic Programmers.
http://pragprog.com/book/ltp2/learn-to-program
From there learn about what MVC is (lots of information out there), which will help with how you understand models, views, controllers, and how they relate.
In my Rails application I'm trying to make the controllers skinnier and am having difficulty with one object that I keep having to pass around.
The object represents a user's facebook session and is instantiated off of the session so it exists in the controller side of things. Many model methods use it, so it is repeatedly passed in as an argument all over the place.
This smells like something, how to DRY it up the Rails way? Thanks!
First, I would recommend using a system similar to Authlogic for your authentication. This gives you two bonuses:
You have proven, stable, tested authentication for your application
The sessions are based like Models, so you can do this kind of stuff...
class Widget < ActiveRecord::Base
def do_facebook_stuff
UserSession.find #This gets you the current session
UserSession.find.record # This gets your the user for the current session
end
end
Now you no longer need to pass the session information in, as you can do basic model-style lookups to find it. In addition to this, Authlogic has a plugin architecture that supports Facebook Connect, which may help you further.
I can give you the CakePHP way (which was originally designed to be like rails).
All CakePHP models extend the same parent AppModel, and all controllers extend an AppController.
I would make an empty parameter in the AppModel that represents your object. Then in the AppController I would store the object in the current model's parameter, if the object exists. There is a callback in the CakePHP AppController called beforeFilter() which fires before any code in the controller. The ideal place to check for the object and store it in the model would be in whatever equivalent Rails has of this beforeFilter callback.
That is unless all models don't use the object. If that is true, you could put the parameter in only the Models that use it (instead of the parent), and then in the beforeFilter of the AppModel you can check first if the Model has that empty parameter.
I know it's not Ruby, but it would look like this:
public function beforeFilter() {
if (isset($this->{$this->modelName}->yourObjectParameter)) {
$this->{$this->modelName}->yourObjectParameter = $this->yourObject;
}
}
$this->modelName is a string that corresponds to the name of the current model. the { } around $this->modelName in PHP is called complex syntax. It basically converts the string into the model object. Not sure how to do the same thing in Ruby.
You can take your method to application controller, something like this
class ApplicationController < ActionController::Base
before_filter :get_facebook_session
def get_facebook_session
#facebook_session = <your code >
end
end
And you can access #facebook_session variable from your controllers and views
cheers
sameera
I am using single table inheritance in StudentHours and TeacherHours, which have a parent Hours.
The model code is mostly in hour.rb, and very little in student_hour.rb and teacher_hour.rb
Now I have realized that most of the controller code is duplicate as well, so I've created a hours_controller to be the parent of students_controller and teachers_controller.
Because the hours_controller instantiates model objects such as TeacherHours.new I've created a accessor in the child classes such as:
def MyModel
#mymodel = "TeacherHours"
end
... then the hours_controller simply calls MyModel.new
Occasionally there are other models that are referenced and sometimes I even call 'render' on a view so I made accessors in the child classes for those too.
I can't find example of others doing this. So, is this bad for any reason, or is there a better way?
Why do you need to use inheritance for the behavior of these models?
This sounds like unnecessary inheritance, both in the models and the controllers.