polymorphic activerecords in rails? - ruby-on-rails

Hi so I have a list of 'areas' that are just areas of my site. I want to be able to insert them in to the database and say what type of area they are, this could be the name of the model that inherits from a base Area. This way I can write a generic controller which uses different views and different logic from the loaded model to decide how the page should act.
Trouble is I have no idea how to do this as I'm new to rails.. Any pointers? (or anyone saying "don't do it like that! do it like this!" would also be much appreciated)
Thanks

I have just found Single Table Inheritance. This appears like it will solve my problem
for more information read here:
http://juixe.com/techknow/index.php/2006/06/03/rails-single-table-inheritance/

You'll want to create a column named :type
Rails will automatically use the type column to determine the class of the child class.
Then you can do something like:
class Area < ActiveRecord::Base
end
class UserPage < Area
end
So then when you do
UserPage.create( :key => 'value')
It will create an entry in your areas table with the type field set to UserPage.

Related

Organization model extends user model

I have User model and Organization model. The only difference is that organization has_many users, all other properties are same. I don't want to put it in one table/model. How can I remove tons of code duplicating in this models? Should I use Concerns? I think, it will be not normal if User model will looks like :
class User < ActiveRecord::Base
include user_concern
end
So, how can I extend user model in other model? And how to generate this model with rails g with all User's fields inside?
beware STI
I would keep with concerns rather than using STI. STI often causes more problem that it solves (type mismatches, form urls, etc), plus inheritance won't make sense, here : an user is not a kind of company, and a company is not a kind of user.
That's a naming problem
I think your problem is a naming one. Obviously, your concern should not be "UserConcern". The question is : what kind of methods do you group in that concern ?
Are your methods about social relation between users ? Then, you need a Socializable concern. Are they about subscribing to mailing list ? Then you need a Subscribable concern.
It's ok to have several ones, even if they have a single method in it, because developers won't wonder "what the hell does this do ?" if all concerns are correctly named.
What to duplicate anyway
You should also probably let class level method calls out concerns.
If it's ok for scopes to be embedded in concerns (after all, they resolve in method definitions), it feels less natural to me to put relations in there.
It's ok to duplicate #has_many :foos, we do it all the time in separate models, and it's already difficult enough to get an idea of table schema from a model without hiding more information.
You could use single table inheritance (STI) for this. To get it to work, your model needs a type-field of type string, in which ActiveRecord stores the actual type of your record. Then, you just extend your base model for this.
migration
add_column :users, :type, :string
models
class User < ActiveRecord::Base and class Organisation < User.
ActiveRecord will now fill your type-field with the model-name, and store both in your users table (since this is the one the organisation model is inheriting from).
Have a look at the according section on http://api.rubyonrails.org/classes/ActiveRecord/Base.html .
However, in your case, I'd create a base model, e.g. Address, and then extend User and Organisation from it, to maintain semantically correct models.

How Do I Call An Array Written in My Model

Greeting all
I would like to create an array in my model and then reference it later from a view or a helper. How do I do this?
This is in my Events model. Users can select a lunch type(1,2,3) for the event. Instead of hard-coding sandwich names, which can change, in my view, I thought I would keep the names in one place (model) then reference the name based on the lunch type chosen.
SANDWICHES = { 1 => 'Turkey', 2 => 'Veggie', 3 => 'Roast Beef' }
How do I call this from another script in my app like a view or a helper?
Event.SANDWICHES[1] does not work
event_obj.SANDWICHES[1] does not work
thanks for any help.
What you have there is a constant and you need to access it with Event::SANDWICHES.
What you are describing here is not a Model (in the rails way), it's simply a constant.
If you don't want to create an actual Model with its own database table, you could pull this out into a helper.
Such as fillings_helper.rb
def fillings
%q{Turkey, Veggie, Roast Beef}
end
Then you can use it in your views for a select box by passing in fillings
http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select
You would need to set up a text field in your Event model to accept a string for fillings.
This isn't necessarily the best way from a database normalisation perspective, but it will do what you're asking for.

What is the proper way to validate the type when using single table inheritance (STI)?

I am trying to use single table inheritance for some of my models. The base model is a Tournament, and I wish to extend this to create different types of tournaments. For instance, I might want to add a SingleEliminationTournament, or a DoubleEliminationTournament, both of which would inherit from Tournament. I have 2 questions, both of them somewhat related.
1) I would like the user to be able to create tournaments with a form, and to do this they would need to select one of the subclasses. Is there a way to get all of the subclasses and use them to populate a select box or something like that?
2) Since this information is going into a form, it would be nice to be able to validate the input into type. To do this, I would like to add a validation in the Tournament class that could check to make sure the Type was valid.
Obviously, I could hard code the values into the validation and the form, but I would not like to do that. Any help would be appreciated. Thanks!
TheModel.subclasses
would give you a list of types you need to include, but only if the models are loaded at runtime. They will always be loaded in production mode. You will have to load them manually in development mode.
You could create a directory with tournaments in them and load them with Dir.glob('app/tournaments/**/*_tournament.rb'). This gives you a nice listing all the tournament files you've specified. Because of convention, you can then infer the proper class name for each tournament.
Store this list of tournament names somewhere for reference in you validations and forms.
I'm not a Rails expert and I'm not sure if this can be considered clean, but for the validation part of your question, this worked for me:
Inside Tournament model:
def validate_type_implemented
klass = type.constantize rescue Object
raise "Given type not available." unless klass.class == Class and klass <= self.class
end

Polymorphic inline model forms in django

I have a Person model which has many Animal models as pets. Dog is an Animal with a "favorite bone" field, and Cat is an Animal with a "likes catnip?" field and a "favorite fish" field.
#models
class Person(db.model):
pass
class Animal(db.model):
models.ForeignKey(Person) #owner
name = CharField()
class Dog(Animal):
favorite_bone = CharField()
class Cat(Animal):
favorite_fish = CharField()
likes_catnip = BooleanField()
I would like to inline edit all of a Persons pets, in the Person admin form however, I've read that Django inline admin forms don't support polymorphic inline forms[1], in that, you will only get the parent class fields (e.g. not the favorite_bone or favorite_fish and likes_catnip fields.
Where does this problem come from?
What changes could be made to the framework to accommodate this?
If these changes should not be made, why not?
[1] http://www.mail-archive.com/django-users#googlegroups.com/msg66410.html
(This is an old question, but I thought I'd add an answer in case it is still useful. I've been working on a similar question recently.)
I believe it would be challenging to change Django form-generation to do what you want. The reason is that the inline formset uses a single class/form for all rows of the inline -- there are no configuration options that are evaluated per-row of the inline form. I have convinced myself of this by reading the code itself --- look for "inline" and "formset" in django.contrib.admin.options.py, especially lines 1039-1047 (version 1.5.1). This is also the reason why you can't have some fields read-only in existing items and changeable in new items (see this SO question, for example).
The workarounds found for the readonly case have involved a custom widget that produces the desired behavior such as this one. That still won't directly support polymorphism, however. I think you would need to end up mapping your divergent types back to a common ancestor (e.g. have all pet classes able to return a dict of their unique attributes and values), and then create a single custom widget that renders out the polymorphic part for you. You'd then have to map the values back on save.
This might be more challenging than it is worth, and may lead back to the suggestion in the other answer to not use admin for this :-)
may have a look here.
but i think the modeladmin is currently not able todo such things.
you are able to create a custom edit view for your model...
there is almost everything possible.
It may be possible to do this with Generic Relations.

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