rails - root model or application model - ruby-on-rails

I was just looking around rails and noticed there is an app controller but no app model.
Is there no root model in rails ? if not where do you put a piece of code that needs to be in every model.
Thanks, Alex

Nothing says your controllers have to subclass ApplicationController but it generally is the standard because the vast majority of rails applications make use of the layout capabilities (which can vary on each controller), so instead of forcing the rare ones without layouts from turning the layout off (layout nil or layout false) for each controller, they make an 'abstract' one that you can turn controller features on and off easily for your whole application.
Now for models, you could create an ApplicationModel for all of your models to subclass, but there are two things to think about:
ActiveRecord normally detects when you subclass an already subclassed ActiveRecord::Base and uses this to turn STI (single table inheritance) on.
ApplicationModel will be an actual model that is expected to have a table in your database. This can lead to problems down the line.
To fix these two problems, you have to set abstract_class to true for ActiveRecord to properly function.
class ApplicationModel < ActiveRecord::Base
self.abstract_class = true
end
In contrast to an abstract ActionController, abstract_class must set to true which means the developer must know they cannot remove this line from ApplicationModel. With ApplicationController you can do pretty much whatever you want to it.

Most models in rails inherit from ActiveRecord::Base which has all of the conventional getters and setters and the association methods, validations and support.
You could extend ActiveRecord::Base in a file in the lib directory (or anywhere in the rails load path really) and any models that are active record models would have the method(s) available. Modules are also a good way of sharing code between many models.

I think I remember some years ago, there actually existed a ann AppModel by default. Is this true or do I mix things up (I haven't been working with Rails for some years until now)?

Related

In Ruby on Rails, does a child class inherit the parent class' associations?

I have an abstract class called Work and another class I called Fanfic. In the Fanfic model, I had that it belongs_to :user and has_many :characters along with other associations. I decided that it would be easier when I add more classes that they will be subclasses of Work instead of having all of the types of works as totally separate classes.
Now I'm wondering if I could write the associations ALL of the works would have in the Work model, with all of the sub-classes keeping all of those associations as well.
Sorry if it's a bit confusing. Let me know if you need clarification or if you need to see my code, or if you need any other information.
Not only should you define associations in Work (super) class (and they will be usable in subclasses), you should also use works table for all the subclasses of Work.
It's typical case of Single Table Inheritance.
To enable it, you just need to add type column to works table (add migration for it).
When you query for Tales, for instance, Rails creates the following SQL query:
SELECT * FROM WORKS WHERE type='Tale';
There is a great (and consice) writeup about this concepts in Rails documentation: http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html

How to structure this so I get all the benefits from STI with none of the consequences? (Pretty irresponsible, I know.)

Say I have the following example of associations in a Rails app:
I'm considering combining the *Posting models under STI. One problem with STI is the potential for many attributes that are only related to one subclass (i.e., a lot of denormalized nil values). This is especially worrisome when your subclasses and going to evolve and grow in the future. I've read a few related posts (such as this), however, as you can see in my example, the potential subclass-specific fields will not necessarily be just attributes, but rather, a lot of belongs_to associations.
My question is, how could I restructure this to use STI from a Posting model for all the common attributes/methods (of which there will be quite a few in my actual app), but keep the unique subclass-specific attributes and belongs_to associations from piling up in the Posting model? Also, the ability to access #board.postings and work with those standard methods is important.
For example, I've thought about moving the type-specific attributes to another model:
class CarPosting < Posting
has_one: car_posting_detail
end
class CarPostingDetail < ActiveRecord::Base
belongs_to :car_posting
belongs_to :car_make
belongs_to :car_model
end
Although, this starts to create a lot of joins, I'm not sure I have the has_one/belongs_to declarations in the right direction, and you have to start chaining calls (e.g., #posting.car_posting_detail.car_make).
Are there other design patterns you have seen for accomplishing this?
You basically have to 2 options for accomplishing inheritance.
First, you can use rails STI as you suggested. The downside is that end up with nil attribute for the child classes that do not use all of the fields. Your idea to reduce this by adding type-specific attributes to another model is a great way to reduce this. However, you should keep the implementation as DRY as possible by defining a has_one :detail for the Posting. Then you can simply assign specific detail types in the Posting childs. For example, CarPosting's detail would be CarPostingDetail. This is convenient because then all Posting children will have their details accessed identically, but will still have different details. So the query now looks like #posting.detail.car_make. To take this one step further, you can define a custom helper method in your Posting model to grab each attribute in the current Posting's detail and create an accessor for it. Now the entire detail layer is transparent and you can simply access those attributes by saying #posting.car_make.
Second, you can use an abstract class. This is essentially the reverse of STI. You create an abstract model class which can never be instantiated. Thus, you cannot define any relationships in the Posting class because it has no table. Each child of the abstract Posting class has its own separate table. The main advantage of doing this would be the ability to define methods for all of your Posting types without copy and pasting them into every model. So this options is better if there are some overlapping functionality across the models, but very little data overlap.
You could use polymorphic associations for this.
Post model belongs_to :postable, :polymorphic => true
car, event and all the other "postable" classes would have this relationship
has_many :posts, as: :postable
Post would hold the postable_id and postable_type
More info here
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

Basic models, understanding the fundamentals of classes (Ruby on Rails)

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.

Is it bad practice to have two controllers for one model in Ruby on Rails?

I have a model that gets treated differently by a parameter it holds, for example its like a character table, which also is used for non player characters, since they share all the same attributes. So it would have a Boolean or integer that would indicate if it was a player character or a non-player character. And non-player characters will be generated automatically with random status parameters and names.
Since the methods used for the two are radically different, I though it would be logical to have a different controller class for them, but that would make a single model have two different controllers, and feels somewhat odd.
Is this bad practice? Should I do all the coding in one controller?
It actually sounds to me like you should have two different models. If the way you interact with the objects is radically different, as you explained, then they really shouldn't be the same class. Ruby has a great way to deal with this case: Modules. You can use modules to create shared behaviors for objects. You can even store the non-player characters and characters in the same database table by overriding the ActiveRecord table name. For example:
module Character
def decrease_hitpoints x
...
end
# other shared functionality can go here
end
class PlayerCharacter < ActiveRecord::Base
set_table_name 'characters'
include Character
end
class NonPlayerCharacter < ActiveRecord::Base
set_table_name 'characters'
include Character
end
In this example both PlayerCharacter and NonPlayerCharacter share the same table name and functionality defined in Character, but they are different objects.
Finally, it's totally fine to use two or more controllers for a single model, just as it's fine to build a controller that doesn't depend on a model at all.
This is completely OK. What you are describing is a task-based user interface, where you are more interested in capturing a work flow or process, as opposed to a simple CRUD or resource operation. Remember, the default setups in Rails are meant to be very basic. Feel free to expand on the basics.

ActiveRecord Inheritance with Different Database Tables

I have just started investigating using more advanced models in Rails. One that I use regularly, with great success, is model where a many-to-many cross-reference relationship is accessed by a class that itself is a sub-class of the base class in the many-to-many relationship.
This way the cross-reference class can act as a stand-in for the base class.
A good example is where a navigation hierarchy node (NavigationNode) is cross-referenced to a user role. At the cross-reference point a class (RoleNavigationNode) can inherit from NavigationNode and still have intimate knowledge of the user role.
My question is (in the case above) can RoleNavigationNode inherit from NavigationNode and yet access the cross-reference table rather than the one that NavigationNode accesses -- this of course using ActiveRecord.
I have not investigated polymorphic association, which may be more appropriate.
Thanks in advance...,
tried set_table_name on the subclass?
Also, look into setting #abstract_class in model classes.
Lastly, what you need may simply be a Mixin that you include in both models.
Anyway, what you're trying to do sounds rather un-ActiveRecord-ish. You might want to post a clearer example of what you're trying to achieve, maybe we'll be able to come up with something simpler.
This works in Rails 3:
class Common < ActiveRecord::Base
#abstract_class = true
def common
"Foobar!"
end
end
class Model < Common
end
class AnotherModel < Common
end
Without setting abstract_class, Rails will look for a table named commons in your database.

Resources