I am having a confusion regarding object modeling, which I will illustrate using a simple lending library project.
The library has books (one copy for each book to keep things simple) and patrons. Patrons can loan a book, if that book is not loaned to another patron.
This will need 3 classes, Book, Patron and Loan.
Book will have an id and a name. Patron will have an id and name. Loan will have an id, book_id, patron_id and loan date.
Where will the loan and return method be defined? Is this a method of book, patron or loan object?
Book is the one getting lended, patron is the one who lends the book and loan is the one who keeps all details about the particular lending operation.
Why is Loan class really needed? Of course the DB table is needed with the fields mentioned above, but from an MVC framework perspective (eg: Symfony or Rails) should this be defined as a model?
I know this is a simple and solved problem, but after being out of touch with oop design for long, I am not quote able to "view" this problem correctly!
Make a class that is responsible for creating a Loan object. You could call this LoanCreator or if it is helpful for you to think of it in the following way you could call it Librarian. You would pass this new class a Book and a Patron object and it would create the Loan for you. Generally if you find yourself unsure if a method should belong to a particular class then perhaps it is time to consider creating a new class.
In my point of view you need 2 classes
Book
Patron
and
loan and return methods should go into Book class as those operations are happening to books. But as you said there should be a different loan table to keep these records.
When coming back to MVC, they should be implemented as models.
Related
I have an application where a User can create many Links, and each Link can store different type of data, depending on what type of Link it is. For example, a TelephoneLinkData stores a telephone number, an EmailLinkData stores an email address, a subject and a body. Each Link also has some fields in common, such as a reference to the user and a name.
I've tried to map this into ActiveRecord as cleanly as I can. Currently, I have a polymorphic relationship from Link to its data-type:
class Link < ApplicationRecord
belongs_to :user
belongs_to :link_data, polymorphic: true
...
class EmailLinkData < ApplicationRecord
has_one :link, as: :link_data
accepts_nested_attributes_for :links
...
Technically, I think this would be described as a reverse polymorphic relationship as instead of a class having possibly different parent classes, what I'm trying to model is a class having multiple possible different child classes. This works fine, and I'm able to create Links through the various *LinkData controllers, but what I'd really want to do is have the Link act as the primary source of interaction for the user, so that the user manages their links through the /links path. For example, I would like the API to allow a User to create a link by posting to /links with the data for the LinkData nested in the link_data field
I've looked around for other ways to model this relationship, and the most common other suggestion seems to be Single-Table Inheritance, but the majority of my columns will differ between LinkData classes, so that feels like the wrong abstraction.
Is there a more idiomatic way to model this data structure?
As is always the case, the best choice depends on the business or application needs, so it's difficult to provide a recommendation without knowing more about what you're trying to do.
It sounds like you prefer the MTI approach, essentially using actual foreign keys and an XOR constraint to the Link table instead of a type column. That's a totally reasonable (although not as common) alternative to a polymorphic association.
However, I think there was a bit of a misunderstanding in your question.
Technically, I think this would be described as a reverse polymorphic relationship as instead of a class having possibly different parent classes...
A polymorphic association in Ruby/Rails doesn't have anything to do with class inheritance (e.g. parents and children). You might be thinking of Single table inheritance. A polymorphic association allows one class (e.g. a Link) to be associated a record in any other table (e.g. the various classes of LinkData) via two fields, a association_id and association_type. These associated classes need not be related to each other. For example, a common use case might be the acts_as_commentable gem, that allows you to add a comment to any other object, and the comment would have a polymorphic association with the other classes.
In the second part of your question you mention that you'd like the User to interact with Link's via a single controller.
I would like the API to allow a User to create a link by posting to /links with the data for the LinkData nested in the link_data field
There's nothing stopping you from implementing this using the initially proposed data model. ActiveRecord may not handle this completely for you out of the box, but you can imagine implementing a link_data= method on the Link class that would create the appropriate associated object.
I'd say the pros/cons of using a polymorphic association would be...
Pros:
easy to setup and use
easy to make required (validate presence of / not null)
easy to associate with a new class
Cons:
no referential / database integrity
have to migrate data if you change a class name
And using the MTI approach is basically the opposite. A bit harder to setup and use, harder to add a new association/table, harder to ensure exactly one association exists... but the long term data quality benefits are significant.
I was able to get things to work the way I wanted to using multiple table inheritance, based largely on this chapter: https://danchak99.wordpress.com/enterprise-rails/chapter-10-multiple-table-inheritance/
I've a quick and quite basic question to ask.
I would like to create a new model which has a parameter that can be one of several model types.
Ex: the param 'targeted_object' can be either an instance of Model A or an instance of Model B.
For the moment I don't think I need a similar behavior for Model A and Model B, so my first guess is to create a Master model for Model A and Model B named TargetableObject: create inheritance.
But is it the best way to do this or I need to make something else regarding that I presume for now no related behavior for Master object children?
Thanks
If I understand correctly, Polymorphic associations could be what you need.
From the rails guides:
With polymorphic associations, a model can belong to more than one other model, on a single association. For example, you might have a picture model that belongs to either an employee model or a product model.
I've got faced with this very basic thing multiple times now, but I never knew how to solve it in the most efficient way.
I have a class 'Student' and a class 'Course'. The student should know all of his courses he visits by a list of courses, and the course should know all the students wich are visiting it by a list of students.
Now let's say I want a student to visit a new course, so I create an 'addCourse(Course course)' method to add a new course to the student's list of courses - no problem. But I also want the course to know about the student is visiting it now. So I create a 'addStudent(Student student)' method for the course class and call it in the student's 'addCourse' method.
The problem is: I want to make those data updates possible from both sides - the students and the courses, but if I would add the respective other method into the own method, I would end up in a stack overflow of course. So how can I prevent this most efficiently?
Also if I store this data in objects of both classes, I guess I would flood my memory with more data than I need. Is there a way to prevent this too without losing access to data?
You have a Student class that has an AddCourse method, which updates the list of courses that the student visits.
You have a Course class that has an AddStudent method, which updates the list of students who are visiting the course.
Somewhere else in your program, you decide that the student is going to visit a course. For example, there might be a user interface that the student interacts with if he wants to join a course. That user's action should trigger a call to some business logic that does everything required to add the student to the course. For example:
function AddStudentToCourse(studentId, courseId)
{
student = GetStudentById(studentId);
student.AddCourse(courseId);
course = GetCourseById(courseId);
course.AddStudent(studentId);
}
The point here is that as far as the Student is concerned, it just maintains a list of course Id numbers. The Student class doesn't actually do anything with the courses; it just maintains the list so that some other piece of code can refer to it later.
Same for the Course; it just maintains a list of student Id numbers.
The beauty of this design is that Student and Course are independent of each other, except for those lists of ids; and those are really just numbers.
I won't say that this is "the most efficient" way to do it. It does work well, though.
I have an article model article.rb (with related images):
attr_accessible :name, :content, :image_ids, :altname1
I now want to create another kind of articles, that are just for cities. They will appear in a completely different section of the website and are not related to all other articles. But the model is exactly the same.
Is it better to create a new model cityarticle.rb or is it better to add a new boolean column (cityarticle with true and false as options) into the existing article model. I'd then add a new action to the controller:
def cityarticles
#cityarticles = Article.where("cityarticle = ?", true)
end
For me it's easier to keep just one model, but there might be good reasons for a new model? How about performance?
Some questions to ask yourself: In what other ways will these types of articles be different? Will different people have access to create/edit/delete them? How do I create a city article and not let it accidentally be saved as a non-city article, or vice versa? Am I using attr_accessible or strong_parameters to prevent users from overriding the article type with params passed in? Will the different types have different validation rules (maybe requiring a city name for city articles)?
How hard will it be to get just the articles I want? How likely am I to forget to specify what kind of articles to show and show all of them?
Based on answers to questions like those, you should be able to decide what data structure will work best for you. If you use Rails' STI pattern, you could wind up with one table but two different models, as one solution. Performance is probably not the main consideration, but if the two types of articles are never going to be queried together, it might be slightly better in terms of performance to split them into separate tables.
New model represents a new "entity" on the System.
Say CityArticles extends Article
It should be a new Model for code clarity and extensibility to increment functionality over the "CityArticles".
You can make a new table scaffold or migration:
rails g scaffold CityArticles references:article
Or making Article class polimorfic association. Read http://teachmetocode.com/articles/ruby-on-rails-what-are-polymorphic-associations/
Lets say there is a activerecord class called user, which is representative of user table of database.
But I have different type of users which have
special functions
special variables
custom relations (Employer has_many companies, Employee belongs_to company :)
But also these users have a lot of functionality in common. So what I want to do is create classes for each different type of user then inherit them from user class.
User < ActiveRecord::Base
Employer < User
Employee < User
Customer < User
What is the best way of doing something like that?
Thanks
A lot of applications start out with a User model of some sort. Over time, as different kinds of users emerge, it might make sense to make a greater distinction between them. Admin and Guest classes are introduced, as subclasses of User. Now, the shared behavior can reside in User, and subtype behavior can be pushed down to subclasses. However, all user data can still reside in the users table.
All you need to do is add a type column to the users table that will hold the name of the class to be instantiated for a given row. Active Record takes care of instantiating the kind of object when it loads it from the database.
This technique is called Single Table Inheritance or STI (for short).
A very good recent article about STI is here: http://code.alexreisner.com/articles/single-table-inheritance-in-rails.html
Have a look to this thread on models subclassing:
Subclassing models in Rails