How do I create and use a polymorphic relationship? - ruby

I am new to Ruby and I read about a "polymorphic relationship".
What I read was over my head. Can you help me understand what a polymorphic relationship is in simple terms?

Expanding on the post suggested by Jinesh, the overall concept can be explained by this:
A belongs_to association is given by a field in a table that points to a record in another table. For example, if you want to model a Person and their address, you have
class Person
has_one :address
end
class Address
belongs_to :person #Has a field person_id
end
But then, if you have another model Company that will use addresses as well, you would have to share the field person_id. So you make it an addressable_id, and both Person and Company are "addressable" objects to the Address model. So, when you specify
class Person
has_one :address, :as => :addressable
end
you're telling Rails that whenever you search for a person's address, it will look on the addresable_id field on the Address table.

Have you looked at this one? http://wiki.rubyonrails.org/howtos/db-relationships/polymorphic
It would be good if you could ask specific questions which you are finding hard to understand so that the community can address that.

Related

Datamapper - create unique index over belongs_to attribute

I'm using DataMapper connected to an SQLite backend. I need to create a Unique index across my four belongs_to columns. Here is the table.
class Score
include DataMapper::Resource
property :id, Serial
property :score, Integer
belongs_to :pageant
belongs_to :candidate
belongs_to :category
belongs_to :judge
#What we want is a UNIQUE INDEX on the four properties!
end
Things I've done:
A unique index on the four via something like :unique_index => :single_score. This works only if you have a property already included.
validates_uniqueness_of, I think the scope only works for a 2-column unique index.
My current solution, which is to just create a dummy field "dont_mind_me", just so I can put :unique_index => single_score in it and everything works. Is this something that's okay to do?
Create an index using raw SQL, SQLite supports a unique index among the four fields.
Basically there are two parts of this question:
Is my solution okay, or should I find another one? I'm at wit's end dealing with what seems to be something trivial, even with raw SQL
How do I create an "after_create_table" hook in DataMapper? The hooks in the documentation only tell about post-CRUD data.

Sinatra with existing database (that doesn't abide by naming conventions)

I have an existing legacy Firebird database with nonstandard table and field names.
I would like to write a Sinatra app that can access it and display information. I've seen stuff like dm-is-reflective that appears to work when a database has proper naming conventions, but how do I use DataMapper (or ActiveRecord whichever is the easiest) to access those tables?
For example, assuming I had these two tables:
Bookshelfs
shelf_id: integer
level: integer
created: timestamp
Book
id: integer
id_of_shelf: integer
title: string
pages: integer
Something like with odd naming conventions that don't follow any set pattern and where one table's record might "own" multiple entries in another table even though there is not foreign_key assigned.
How would you set up datamapper (or activerecord) to communicate with it?
Look in to this gem to get setup with ActiveRecord on Sinatra:
https://github.com/bmizerany/sinatra-activerecord
As for how to define the relations, activerecord can do this easily.
class Book < ActiveRecord::Base
belongs_to :bookshelf, :class_name => 'Bookshelf', :foreign_key => 'id_of_shelf'
end
class Bookshelf < ActiveRecord::Base
has_many :books, :class_name => 'Book', :foreign_key => 'id_of_shelf'
end
Assuming you figured out how to connect to your legacy database using ActiveRecord's Firebird adapter, the next thing I would do is define a view on top of each table, e.g.
CREATE VIEW books AS SELECT * FROM Book;
CREATE VIEW bookshelves AS SELECT * FROM Bookshelfs;
This way you can simply define models Book and Bookshelf in ActiveRecord as per usual and it will find everything in the right place inside the database.

How do you create resource route when the item has optional child items?

How do you create routes for models that have option child properties? Say I am creating a help desk app, and the ticket could be associated with an order that the customer had previously had with me, or it could be regarding an item in the catalog they have not yet ordered.
class CustomerServiceTicket
belongs_to :order
belongs_to :item
belongs_to :buyer
belongs_to :customer_service_category
end
class Order
...
has_one :customer_service_ticket
...
end
class Item
...
has_one :customer_service_ticket
...
end
in the schema for customer_service_ticket, order_id and item_id are nullable.
So I'll have a 'create a customer service ticket' link next to their say their order_id's on the their closed orders page...and a similar link next to the item_id on the product catalog page.
I'm thinking the url structure should look like this:
customer_service_ticket/new/order/123
for tickets created relating to an order
and
customer_service_ticket/new/item/789
for tickets created relating to an item
and just
customer_service_ticket/new
when there is neither (also valid for cases where the customer just has a general question)
How would I structure the routes to be the most efficient? I'm not married to that URL structure above, if there is a better way I'm happy to try it.
Based on how you describe your routes, it sounds like the orders and items already exist at the time you need to create a new customer service ticket, is that correct? If so, then it would be better to create your routes like this:
orders/123/customer_service_ticket/new
items/123/customer_service_ticket/new
customer_service_tickets/new
Any time you are adding a resource onto an existing resource, the new resource typically goes at the end, with the action you are performing being the last portion of the URL. To create this structure it would be something like this:
resources :orders do
resource :customer_service_ticket
end
resources :items do
resource :customer_service_ticket
end
resources :customer_service_ticket
However, you may also want to rethink your relationships. Once a customer service is closed for an order/item, are you certain there will never be another customer service ticket relating to that order/item? That may indicate a has_many relationship. You may also want to look into a polymorphic relationship for orders and items to customer service tickets. That way if you want to add more entities that can relate to customer service tickets, you don't have to keep adding database fields. Note that changing to a has_many would change the routes declarations above slightly.

How to set up two models having a has_many association with each other

I'm looking for a suggestion on how to set up two models, Teacher and Subject. A Teacher can have many Subjects, and a Subject can have many Teachers. Another thing to consider in the relationship between the two models is that a Teacher can create a Subject and add other Teachers to the Subject.
I think I'm solid on the basics of the set up for each model:
for teacher.rb:
has_many :subjects
for subject.rb:
has_many :teachers
and the teachers table should have a subject_id column and the subject table should have a teacher_id column.
What I'm not sure about is how to set up the views (and corresponding controller methods) to allow the addition of a Teacher to a Subject.
Any suggestions (or links to examples) are greatly appreciated. I haven't been able to find anything on this exact case.
current set up:
standard CRUD for a Student object
standard CRUD for a Project object
I'm likely missing something simple in how to tie these models together (other than the part of changing has_many to habtm) and getting records into the subjects_teachers table, and I still can't find a good example...
You need to build the relational table between them. It's impossible to have a many-many relationship without a rel table
First off though, it's a has_and_belongs_to_many :subjects and has_and_belongs_to_many :teachers (commonly referred to as habtm)
http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association
run
rails g migration subjects_teachers
open up the migration:
create_table :subjects_teachers, :id => false do |t| # ID => FALSE = IMPORTANT
t.references :subject
t.references :teacher
# NO TIMESTAMPS
end
run
rake db:migrate and you should be set!
then
see these railscasts for setting up your controllers
http://railscasts.com/episodes/17-habtm-checkboxes
http://railscasts.com/episodes/47-two-many-to-many

Can Rails Active Record understand two simultaneous relationships between two tables at once?

I have two tables, users and groups. A user can belong to many groups. A group can have many users.
So I have created a have_and_belongs_to_many relationship between users and groups using a join table, groups_users. This all works as expected.
What I would also like to do is specify an ACTIVE group for each user. Were it not for the habtm relationship I have already defined, I would create a column “group_id” in users for the active group, and then I would define a one-to-many relationship between the models as follows:
class User < ActiveRecord::Base
belongs_to :group
end
class Group < ActiveRecord::Base
has_many :users
end
This didn’t work. I could not access group properties like “#user.group.name”. I suspect that I’m asking too much of Rails by specifying two relationships.
So I have three questions.
I could very easily understand if combining the two relationships confuses Active Record . Is that the case?
If so, how would you implement these relationships? Right now I’m just manually using the group_id, but that feels messy.
Regardless of whether I am using Active Record magic or manually setting the active group, it is possible for a user’s active group to be outside the group’s they belong to using the first habtm relationship. Any thoughts on how to implement this with the constraint that the active group must be a group that the user belongs to?
Thanks for any insights. I am a couple of weeks into the Rails learning curve and I think that getting to the bottom of this little problem will deepen my understanding of models and table relationships quite a bit.
Greg - I've done this before, similar to what as your proposing. I used a "primary_group" instead of "group" and set the foreign_key to be "primary_group_id" and the :class_name => 'Group'
I don't use has_and_belongs_to_many very often so I don't know if that would be causing an issue, but I don't think so - at least not with the user model. You don't have a #group method, so setting belongs_to should be OK. I don't know if you absolutely must have have a has_many :users method on the group, but you may not need it anyway. This will certainly cause a collision with the 'users' method that habtm creates. If you do need this, try has_many :primary_users and set the :foreign_key => :primary_group_id
Just some thoughts. You should be able to do what you're doing now, so not sure what's failing.

Resources