how to handle "synonymns" in a has_many relationship - ruby-on-rails

This is a bit of a sticky issue. I have a Rails association but need to add functionality to handle some special cases.
class Item < ActiveRecord::Base
has_many :notes
end
class Note < ActiveRecord::Base
belongs_to :item
end
The issue is that you could have something like this in db (identical items that might have a difference in sizing or quantity but are part of the desc and can't really be broken out due to accounting software):
items
id desc
1 a glass something
..
10 a bottle of something
..
20 a case of bottles of something
notes
id note item_id
3 "a note about something" 1
What I want to do is create a linke so that items 1,10, and 20, when they load notes, will all load notes with an id of 1
For example:
item1=Item.find(1)
item1.notes[0].id # 3
item10=Item.find(10)
item10.notes[0].id # 3
item20=Item.find(20)
item20.notes[0].id # 3
I feel like there should be a really basic way of doing this and was looking for suggestions. This is hacky but might work would be to write a dash separated list of other_ids into the notes table so that a notes.other_ids="-10--20-"
class Item < ActiveRecord::Base
has_many :notes
def sym_items
Note.where('other_ids like ?',"%-#{self.id}-%")
end
end
We really would only have to deal with this in a single scenario so a hacky sol'n woudl be ok but obviously would like better. Possibly do a has_many :through. I'm not sure about the latter - perhaps too much added complexity. Any help or advice would be appreciated.
thx

So I'm not sure I fully understand the situation. It seems like you might want something like this:
class Item < ActiveRecord::Base
has_many :notes
has_many :other_item_notes
has_many :other_notes, class_name: "Note", through: :other_item_notes, source: :note
has_many :other_items, class_name: "Item", through: :notes, source: :other_items
end
class Note < ActiveRecord::Base
belongs_to :item
has_many :other_item_notes
has_many :other_items, class_name: "Item", through: :other_item_notes, source: :item
end
class OtherItemNote < ActiveRecord::Base
belongs_to :item
belongs_to :note
end
The trick here is that you have a many-to-many association between items and notes (I assume you know how/why those other associations are supposed to work). Then we use the associations of those other items that we can now access to access their associated items. There may be complications with N+1 queries and such, but some of that can be dealt with by using inverse_of on your associations.
If you do it this way, you are querying against indexed id columns in your database searches, rather than a string comparison query like in your example above.

Related

ActiveRecord: has_many choices limited to has_many of another model

I would like to achieve something as follows where PersonSubject has many topics, but the choices of these topics are limited to the the selection of topics through another model (ie: through the associated subject):
class Topic < ApplicationRecord
belongs_to :subject
end
class Subject < ApplicationRecord
has_many :topics
end
class PersonSubject < ApplicationRecord
belongs_to :person
belongs_to :subject
has_many :topics # where the choices are limited to the subject.skills
end
I would then like if any person_subject.subject.topics are deleted (or association removed), it would automatically update the person_subject.topics to no longer "point" to the Topic(s) that were deleted.
Is this possible?
You can use a lambda to put arbitrary filters on an association. See What is the equivalent of the has_many 'conditions' option in Rails 4?
has_many :topics, -> { where(skill: subject.skills) }
I don't know that this is exact code will work without seeing your schema (what is the data type of subject.skills, and how do you join this with topic?). But hopefully this gets you on the right track
edit
in response to your comment, I think
has_many :topics, through: :skills
would work

Layers of associations and descriptions on rails

I am trying to implement a resume feature and I was wondering the best practice for handling it. Lets assume a user has 2 pieces to a resume, education and work experience, and this is constant among all users. Then under each I want to save titles of things they've done (eg. Attended school at ______, worked at ________, project doing _______). Within these I want to save a description of that specific activity. What would be the best practice for implementing this?
So I need some association like: a user has_many experiences. An experience has_many titles. A title has_many descriptions. I also need to make the title of the experience is associated with the correct header (education or work experience).
I'm still pretty new to rails, and I'm sure there is a much easier and intuitive way to do this. Thanks for the help!
You can try these simple models structure for
class User < ActiveRecord::Base
has_many :locations
has_many :projects, through: experience_projects
end
class Location < ActiveRecord::Base
belongs_to :user
end
class Experience < ActiveRecord::Base
#experiences table should contain title and descriptions
belongs_to :user
has_many :projects, through: experience_projects
end
Now Join model if you do not require this intervention model you can directly use has_and_belongs_to_many
class ExperienceProject < ActiveRecord::Base
belongs_to :user
belongs_to :experience
end

Newbie here: conflict associations to the same table. has_many:invoices, has_many :invoices, through: user_invoice_viewers

this seems pretty basic stuff here, but actually i'm finding it a bit harsh to define this scenario with Rails...
Perhaps any of you can provide some guidance?
So I have three Tables, Users, Invoices, and User_Invoice_Viewers (these basically map users that have viewer access to an invoice)
Now my models :
User.rb :
has_many :invoices
has_many :user_invoice_viewers
has_many :invoices, through :user_invoice_viewers
Invoice.rb
belongs_to user_invoice_viewers
belongs_to :user
User_Invoice_Viewers.rb
belongs_to :users
belongs_to :invoices
Now this just seems wrong... I repeat has_many :invoices on User model, so i expect conflict when executing : User.invoices ...
What would be the best solution for this? I had thought of putting it all on a user_invoice table, but since i expect to have more owners than viewers, for performance reasons, i decided to build a direct dependency between invoice and its owner...
Thanks
I would consider using the :class_name option on the association, so that the two relationships are named differently. Something like this:
class User < ActiveRecord::Base
has_many :invoices
has_many :user_invoice_viewers
has_many :viewable_invoices, through :user_invoice_viewers, :class_name => "Invoice"
...
end

Proper Rails Association to use

I am trying to create an association between two tables. A student table and a computer table.
A computer can only ever be assigned to one student (at any one time) but a student can be assigned to multiple computers.
This is what I currently have in mind. Setting up a has-many through relationship and modifying it a bit.
class Student < ActiveRecord::Base
has_many :assignemnts
has_many :computers, :through => :assignments
end
class Computer < ActiveRecord::Base
has_one :assignment
has_one :student, :through => :assignments
end
class Assignment < ActiveRecord::Base
belongs_to :student
belongs_to :computer
end
Does this seem like the best way to handle this problem? Or something better sound out quickly to the experts here. Thanks!
You need first to decide if a simple one-to many relationship is enough for you.
If yes, it gets a lot easier, because you can get rid of the Assignment-class and table.
Your database-table "computers" then needs a student_id column, with a non-unique index
Your models should look like this:
class Computer < ActiveRecord::Base
belongs_to :student
end
class Student < ActiveRecord::Base
has_many :computers, :dependent => :nullify
end
"dependent nullify" because you don't want to delete a computer when a student is deleted, but instead mark it as free.
Each of your computers can only be assigned to a single student, but you can reassign it to a different student, for example in the next year.
Actually your approach is fine, as one offered by #alexkv. It is more discussion, than question.
Another thing if you want to use mapping table for some other purposes, like storing additional fields - then your approach is the best thing. In has_many :through table for the join model has a primary key and can contain attributes just like any other model.
From api.rubyonrails.org:
Choosing which way to build a many-to-many relationship is not always
simple. If you need to work with the relationship model as its own
entity, use has_many :through. Use has_and_belongs_to_many when
working with legacy schemas or when you never work directly with the
relationship itself.
I can advise you read this, to understand what approach better to choose in your situation:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
http://blog.hasmanythrough.com/2006/4/20/many-to-many-dance-off
You can also use has_and_belongs_to_many method. In your case it will be:
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers, :join_table => 'assignments',
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student, :join_table => 'assignments',
end
or you can rename assignments table to computers_students and remove join_table
class Student < ActiveRecord::Base
has_many :assignemnts
has_and_belongs_to_many :computers
end
class Computer < ActiveRecord::Base
has_one :assignment
has_and_belongs_to_many :student
end

How to properly create records using :through?

I have a database like so:
class Store
hasMany :items
class Item
belongsTo :store
class Order
hasMany :items, :through => :order_items
class OrderItem
belongsTo :order
First off, is this the correct way to set up this database?
And finally, how do you create records properly with multiple items?
eg.
o = Order.new
Order.items = [ [0,1], [3,4] ] # do you add them as an array? [order_id, item_id] ?
Am I on the right track for this?
Thanks!
I think you should start here: association basics. Rails has great documentation unlike a lot of other frameworks. It is very easy to digest and makes a great deal of sense. Also picking up a good Intro to Rails 3 book would be well advised.
To answer your question though, there are a few problems with your example above. for starters, it is has_many and belongs_to rather than hasMany and belongsTo. In terms of your modeling, you were close although I would object to your current structure.
The reason I object is because an Order should be a record that snapshots the item as it were at that given instance. Now, if you version your items, then your schema works perfectly fine. If you do not, then you need to be sure to record the relevant information about the product at the time of the order and only have the Item reference for minimal usage.
To answer the structuring question, with the way it is designed now, here is how you'd model it:
class Store < ActiveRecord::Base
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :store
has_many :order_items
end
class Order < ActiveRecord::Base
has_many :order_items
has_many :items, :through => :order_items
end
class OrderItem < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
On to your next question:
And finally, how do you create records properly with multiple items?
#order.items << item #where item is the instance of the item you want to add

Resources