Unique Association :through - ruby-on-rails-3

I have a many to many :through relationship between a set of classes like so:
class Company
has_many :shares
has_many :users, :through => :shares, :uniq => true
end
class User
has_many :shares
has_many :companys, :through => :shares, uniq => true
end
class Share
belongs_to :company
belongs_to :user
end
I want to ensure a unique relationship so that a user can only have one share in any one company, which is what I have tried to achieve using the "uniq" argument.
At first I thought this was working, however it seems the behaviour os the "uniq" is to filter on the SELECT of the record, not pre-INSERT so I still get duplicate records in the database, which becomes an issue if I want to start dealing with the :shares association directly, as calling user.shares will return duplicate records if they exist.
Can anyone help with an approach which would force truely uniq relationships? so that if I try adding the second relationships between a user and a company it will reject it and only keep the original?

Have you tried adding this to your Share class?
validates_uniqueness_of :user, scope: :company
Also, in your User class I think it should be:
has_many :companies, through: :shares
I hope that helps.

Related

Rails Belongs to with different column names

I am developing some voting software where a user gets to vote for 3 different entries. For the votes model I was thinking of something like:
Votes:
Email Address - String
Verification Code - String
Verified - Boolean
First - Entry
Second - Entry
Third - Entry
Where Entry is another model in my rails application. How could I have a belongs to relationship for this? As i'd like to run queries like get the entries with the highest number of votes for first place. Is this the best approach to this problem?
User Model:
has_many :votes, :dependent => :destroy
has_many :entries, :through => :votes
Entry Model
has_many :votes, :dependent => :destroy
has_many :users, :through => :votes
Vote Model
belongs_to :user
belongs_to :entry
I would design the Vote object such that it contains just a user_id and an entry_id. Then your application logic would enforce that if they've already voted three times, they don't get to vote again. That way, when you query for the highest number of votes, you don't have to write special cases for the first, second and third entries.
As far as the belongs_to declaration, I would say that a vote belongs_to both User and Entry, and should be destroyed when either dependent object is destroyed, thus:
class Vote < ActiveRecord::Base
belongs_to :user, :dependent => :destroy
belongs_to :entry, :dependent => :destroy
end

rails model doubts has_one, has_many, belongs_to

I have created 3 models for a small system. The intent here is to handle users, companies and their relationships. I anticipate to do a lot of lookups over the intersections and also want to have strict controls over the joins available, in that a user can only belong to one company, but company can have many users. I feel the best way to represent this is with the below. I would like some feedback on this preposition. So far my tests have worked fine validating my thesis and some small implementation efforts have gone fine, but when I look through a list of users to find their company I somehow run into issues and I have a feeling it is related to the has_one relationship, but not sure. Again thanks for constructive feedback.
class User < ActiveRecord::Base
has_one :companyrelationship, foreign_key: "user_id"
has_one :company, :through => :companyrelationship, dependent: :destroy
class Company < ActiveRecord::Base
has_many :companyrelationships
has_many :users, :through => :companyrelationships
class CompanyRelationship < ActiveRecord::Base
belongs_to :company
belongs_to :user
validates :user_id, presence: true, uniqueness: true
validates :company_id, presence: true
I do see one thing that I'm pretty sure is an error and won't work. I can also try to add a couple points of constructive criticism.
The error is that the CamelCase model name is converted to underscorey (sorry, I can't remember the term for that right now) case. All your references to companyrelationship should add an underscore. You can override the convention by setting the :class_name attribute, but I don't think that's what you wanted.
Another issue I see which isn't technically wrong, but is almost certainly not what you want is that the dependent: :destroy would delete the Company when you deleted a User. (Actually, I'm not sure dependent: :destroy works in a through: relationship.) I assume what you wanted was just to delete the CompanyRelationship. You can read the section on Dependent associations at this link:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Next point is that the default foreign_key is the model + _id so you don't need to specify it in this case.
My last point is purely a style preference. I like doing my validations by validation type. You're doing them by variable. They are functionally equivalent, so feel to take it with a grain of salt. (I'm pretty sure user and user_id are equivalent, but feel free to stick to user_id if you're more comfortable with it.)
If it were completely up to me, I would code it this way:
class User < ActiveRecord::Base
has_one :company_relationship, dependent: :destroy
has_one :company, through: :company_relationship
class Company < ActiveRecord::Base
has_many :company_relationships
has_many :users, through: :company_relationships
class CompanyRelationship < ActiveRecord::Base
belongs_to :company
belongs_to :user
validates_presence_of :user, :company
validates_uniqueness_of :user
I hope that helps you get further.

Searching a has_many :through association including the middle model

First, the topic.
I have three models, which are linked between each other with a has_many :trough association like this:
#User model
has_many :chars_del, :class_name => CharDelegated, :dependent => :destroy
has_many :chars, :through => :chars_del
#CharDelegated model
#has a field owner:integer
belongs_to :char
belongs_to :user
#Char model
#has fields name:string
has_many :chars_del, :class_name => CharDelegated
has_many :users, :through => :chars_del
What I need to do is I need to search from a User Record to find all the Chars that the particular user ownes (:owner field is true) ordered by name. I have been stuck with this for a couple hours now, so I believe that I could have missed a very simple answer... But nothing that I have tried so far did work even a bit.
UPDATE
found something that works:
user.chars.where(:char_delegateds => {:owner => 1}).order('name')
don't know why the :chars_del gave an error, but the full table name did the job.
Andrew, your answer works well too and is a little faster on the database, thans alot.
Does
user.chars.order('name')
not work? (Given user is a single User instance.)
Edit
Given your new information:
CharDelegated.where(user_id: user.id, owner: true).map(&:char)
should work.
In your specific example you don't need to search through the middle table but if you want to see an example of how to use the joining table and search through it for a more complex scenario you can do it this way.
#char = Char.all(:include => :users, :conditions => ["char_delegated.user_id in (?)", user_id]).order('name')

Rails basic association

I'm trying to do a basic model association in rails.
Basically I have a List table which stores item_id and user_id.
One user can create multiple "list-items."
Is this the correct way to do it?
Thanks.
class Item < ActiveRecord::Base
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :items, :through => :lists
end
class List < ActiveRecord::Base
belongs_to :user
belongs_to :item
end
Depending on what you want to reach, your solution is the right one (or not). I see the following cases:
You want to create an n:m association between items and users. So each item could be referenced by many users, and each user references many items. If this is the right context, then your solution is the right one. See the Rails Guides: Associations for more information on that.
An alternative for that situation could be to use the has_and_belongs_to_many Association. The situation is the same, but it does not make sense to talk about lists, there will be no model object for it.
If each users may have many lists, and each list may have many items, your solution would be wrong. This would be no n:m association with list as the join table in between, but two 1:n relations.
The code for the third example would look like that:
class User < ActiveRecord::Base
has_many :items, :through => :lists
has_many :lists
end
class List < ActiveRecord::Base
has_many :items
belongs_to :user
end
class Item < ActiveRecord::Base
belongs_to :list
end
In the first solution, you should add the relations for users to lists and items to list:
class Item < ActiveRecord::Base
has_many :lists
has_many :users, :through => :lists
end
class User < ActiveRecord::Base
has_many :lists
has_many :items, :through => :lists
end
If the "list" entity truly is a pure association/join, that is, it has no inherent attributes of its own, then you can simplify a bit and use has_and_belongs_to_many. Then you don't need a "List" class.
class Item < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :items
end
Rails will look for the references in a "items_users" table, so in your migration, you need to create it a la:
create_table :items_users, :id => false do |t|
t.references :users, :items
end
Many people will tell you to always use has_many :through, but others (like me) will disagree - use the right tool for job.

HABTM Polymorphic Relationship

I'm pretty new to Rails, and i'm trying to do a polymorphic HABTM relationship. The problem is that I have three models that I want to relate.
The first one is the Event model and then are two kind of attendees: Users and Contacts.
What I want to do is to be able to relate as an attendee both users and contacts. So, what i have right now in my code is:
Event Model
has_and_belongs_to_many :attendees, :polymorphic => true
User Model
has_and_belongs_to_many :events, :as => :attendees
Contact Model
has_and_belongs_to_may :events, :as => :attendees
How the HABTM table migration needs to be? I'm a little confused and i have found no help on that.
Is it going to work?
No, you can't do that, there's no such thing as a polymorphic has_and_belongs_to_many association.
What you can do is create a middle model. It would probably be something like this:
class Subscription < ActiveRecord::Base
belongs_to :attendee, :polymorphic => true
belongs_to :event
end
class Event < ActiveRecord::Base
has_many :subscriptions
end
class User < ActiveRecord::Base
has_many :subscriptions, :as => :attendee
has_many :events, :through => :subscriptions
end
class Contact < ActiveRecord::Base
has_many :subscriptions, :as => :attendee
has_many :events, :through => :subscriptions
end
This way the Subscription model behaves like the link table in a N:N relationship but allows you to have the polymorphic behavior to the Event.
Resolveu parcialmente.
It does solve the problem given the framework that we have at our disposal, but it adds "unnecessary" complexity and code. By creating an intermediary model (which I will call B), and given A -> B -> C being "A has_many B's which has_many C's", we have another AR Model which will load one more AR class implementation into memory once it is loaded, and will instantiate for the sole purpose of reaching C instances. You can always say, if you use the :through association, you don't load the B association, but then you'll be left with an even more obsolete model, which will only be there to see the caravan pass by.
In fact, this might be a feature that is missing from Active Record. I would propose it as a feature to add, since it has been cause of concern for myself (that's how I landed in this post hoping to find a solution :) ).
Cumprimentos