i'm a super newbie in rails and i need to see a sample code on how to implement Single table iheritance, i have a model called Listing as a super class, and i have subclasses LawFirms and Paralegal, these all extend the Listing model, now i need to be able to create a new listing, but when i am creating i need the form to have an option to select either Law Firm or Paralegal, when Law Firm option is selected, it should show a form for creating a LawFirm object which is different from the Paralegal Object because a law firm has advocates and a paralegal wont have advocates.
So far my models look like this
class Listing < ActiveRecord::Base
end
class LawFirm < Listing
has_many :advocates
end
class Paralegal < Listing
end
How do i create the controller? and the form?
I'm not sure that inheritance is the right solution for this. Inheritance is used for an is-a relationship. For example, a Nissan is a car so Nissan would inherit from the car class. You might be better off having LawFrim or Paralegal as objects in a Listing using a nested resource in rails. You could then add some checks in the controller to make sure it only has one or the other of those objects.
Related
I have the class User, and subclasses Admin and Student.
Student should have additional dedicated columns. Please let me know how I can do this using STI in Ruby on Rails.
Thanks!
Also, how do I populate the users table?
In Rails, typically you'd have type column on the User class. Now in your subclasses you'd inherit from the User class as such:
class User
end
class Admin < User
end
class Student < User
end
This way you can take advantage of the Rails STI and still be able to flexibly create methods for your subclasses.
Find more information here
However to keep it a bit organized, you could put the subclasses in a folder under your models, as such
#models/users/admin.rb
module Users
class Admin < User
end
end
#model/users/student.rb
module Users
class Student < User
end
end
Now to use your classes, you'd do Users::Student.find(id)
UPDATE
In response to the comment, I think for the columns that would be specific to the student, you'd be better served by an association, say Student.has_one :grade or something of sorts, this way you'd have successfully abstracted your user object to deal with the common User methods. But to create a row for Student and Admin
You could do Users::Student.create(params) or Users::Admin.create(params) and Rails knows how to deal with the STI
I'm new to Rails, still getting my feet wet, so please pardon me if this is either trivial or "the wrong way" to do things.
I'd like to create a superclass for some scaffolded models. For example, I'd like to create a scaffold for Men and for Women, but I want them both to inherit from a People superclass; Men and Women would inherit fields like height and weight from the People class.
Where/how do I define this People superclass? How do I define the subclasses Men and Women via scaffolding?
Usually I do something like:
rails g scaffold People type:string name:string birth:date height:integer
class People < ActiveRecord::Base
end
Important use the reserved word 'type'! That's where the table will keep which type the class is. Run the migration.
So, for the the subclasses you can do:
rails g scaffold Men --parent=People
resulting Men:
class Men < People
end
Same for Women:
rails g scaffold Women --parent=People
Resulting
class Women < People
end
No migration will be generated for the subclasses.
I'm not sure but this approach only works for STI.
Hope it, helps!
This is something I've thought about doing with my application. I haven't done it yet, and I wouldn't recommend it if you are new to rails. I would either make separate models entirely, or make one model, and have the attribute gender, which should be either a 0 or a 1, and then make a method that returns the string for the corresponding gender.
EDIT
So I opened up the rails console, and from what I could see, it is possible totally possible, all you need to do is declare the class, and if you want to use different tables, set_table_name
class This < That
set_table_name :this
end
class There < This
set_table_name :there
end
Or you could use one table, but if your trying to stay DRY, I would use two.
If you want to use the scaffold generator, you will have to run the typical rails g scaffold Men for each class you want views for (men and women). The model that this generates inherits from the ActiveRecord::Base class. The inheritance marker is the less than symbol (<).
# THESE WILL BE THE DEFAULT GENERATED MODELS
class Men < ActiveRecord::Base
end
class Women < ActiveRecord::Base
end
You will then manually create the super class User
class User < ActiveRecord::Base
end
and then edit the Men and Women models to inherit from User
# men.rb
class Men < User
end
# women.rb
class Women < User
end
lets say you wanted to subclass with one table, you could would right the migrations for that table, and then add the attr_accessible to the appropriate subclass.
attr_accessible is a rails security feature. It determines which attributes may be set in mass assignment. Anything related to security, site rank, etc. should not be accessible.
Example:
attr_accessible :favorite_food, :interests, :password, :email # THIS IS GOOD
attr_accessible :admin, :has_access_to_missile_launch_codes # THIS IS BAD
because then someone could undermine your security system by passing
params => { :man => { :admin => true }}
The main point is that using these attr_accessible will determine which type of user can set what. Obviously you can DRY this up by putting shared features in the super-class. Hope this helps
You should also read about the super keyword, and the self keyword. If your running an inherited setup you will eventually want to use these.
AFAIK you'd need to tweak the existing scaffolding templates, I don't believe there's a means to specify the controller base class. That said, I think in Rails 3 you can copy the templates into $ROOT/lib/templates/rails/... where ... depends on which you want to change.
That said, what's the real goal in doing this in a scaffold? In general, models will (a) only rarely be subclasses, and (b) even more rarely be the same subclass.
Just edit them by hand.
watch this screencast on single table inheritance.
http://railscasts.com/episodes/394-sti-and-polymorphic-associations
Single table inheritance and where to use it in Rails
Suppose that I've two controllers, "good" and "customer" and that I want add many goods to a single customer; in which way can I do this?
I mean, I need a customer's show view that list all goods associated to that project and a "add good to customer" used to add a new object to customer.
You would want to do that at the model level with an association and then allow for nested attributes.
It might look like this
model
class customer < ActiveRecord::Base
has_one :goods
accepts_nested_attributes_for :goods
end
Then in the views for customer you would want to have the nested form. This Railscast gives a good overview for that. Because of the association and the accepts you can automatically inherit them in the controller. Also there is a similar question here that amplifies the explanation.
I'm trying to build a student portal in Rails 3, but I'm having some problem.
The idea is to have a users table that contains all basic data for a given person. See the UML/E-R below for example attributes.
A user can be both an Assistant and a Student at the same time.
Assistant and Student should inherit from User.
The idea was to inherit directly from the User, like this.
class User < ActiveRecord::Base
# ...
def awesome?
[true, false].sample
end
# ...
end
class Student < User
has_one :student
has_many :registered_courses, through: :students
end
Student.new.awesome?
This makes the relations in the student model very strange.
has_many :registered_courses, through: :students
I want to be able to do something like this in the end.
student.full_name
student.pin_code
student.registered_courses
One solution would be to implementing the method by hand, like this
class Student < User
has_one :student
def pin_number
student.pin_number
end
end
But it looks really strange to refer to a student object inside the student model.
Is there a clearer, better way of doing this?
Here is an example UML/E-R. I've tried to keep this example clean by removing non relevant attributes. That is why there are so few attributes in the registered course entity.
STI is not a good choice for this the way that you have articulated it here, since users can be both students and assistants. When you are using STI, you generally add a type column to specify which subclass the record really belongs to. If both Student and Assistant inherit from User, then that really isn't an option, since you'd be forced to create duplicate User records for someone who is both an Assistant and a Student.
I think you'd be better off simply having Student and Assistant rows that belong_to a Student, and then delegating the elements that are contained in User back to the User object.
I feel like Inheritance is a bad move here. If you're going to have STI like this it HAS to be one or the other.
Instead throw all your logic into the User model, all your data is there anyway. Plus since Student & Assistant aren't mutually exclusive there shouldn't be any methods that will override each other.
Why not STI?
STI is mainly meant for objects that contain the same data, but does different things with them.
For example, I have a specification that contains multiple processes(ex. build and test). So I have a order that contains processes.
process_1:
order_id: 1
specification: foo
type: build
process_2:
order_id: 1
specification: foo
type: test
In this example the only thing that changes in the data is the type, but because the type changes I know what process to perform from the specification.
I would like to use form_for except I have class table inheritance models using the citier gem. They are defined as such:
class Fruit < ActiveRecord::Base
# calories:integer
# color:string
end
class Apple < Fruit
# is_sauce:boolean
end
class Banana < Fruit
# is_peeled:boolean
end
The problem is that I want the first part of my form to fill out attributes for my Fruit model. Then depending on a select field on what type of fruit (Apple, Banana), I then want to fill out attributes for that particular model yet I still want validations with the form_for helper. Any suggestions on how I can approach this... or additional clarification? Thanks.
What I ended up doing was asking for the model before creating the form. Then using many partials.