rails models association scenario - ruby-on-rails

users => has_many :contacts, :through => :user_contacts
contacts => has_many :users, :through => :user_contacts
profiles
now for profiles, there's a single profile for each user but there are two ways to access it, based on the url. There's a public url and a private url. A public url belongs to a user but the private url belongs to a contact (i.e assigned to the contact as a private url to the profile of the user to which that contact belongs). I'm confused how to treat profiles association with user and contacts in this scenario.
should i use STI for profiles like class Profile < ActiveRecord::Base, class PublicProfile < Profile, class PrivateProfile < Profile
but if that's valid, how do i manage the associations here?

what about simply having a single url type and differentiating with a type in the table. Then you can have the relationships for each TYPE of url with something along the lines of:
belongs_to :private_url, :class_name => "Profiles", :conditions => "type = 0"
belongs_to :public_url, :class_name => "Profiles", :conditions => "type = 1"
This would significantly "simplify" your assciations you have to manage. It's not the whole answer I don't think but perhaps if you can make it work this simplifies things enough that the problem you have becomes simpler to address.
I may have the exact syntax above incorrect but you should get the gist of what I'm suggesting...

Related

Rails - AssociationTypeMismatch error with associating a model with multiple instances of another model

I have two models, Accounts and CreditRecords. An account can have many credit records that belong to it. However, accounts can also trade credit records to other accounts, and I want to keep track of who the current account owner is, and who the original owner is.
class Account < ActiveRecord::Base
has_many :credit_records
class CreditRecord < ActiveRecord::Base
belongs_to :original_owner_id, :class_name => "Account"
belongs_to :account_id, :class_name => "Account"
When I try to set a CreditRecord.account_id to, say, 1, it updates fine. But if I try to set CreditRecord.original_owner_id to 3, I get this error:
ActiveRecord::AssociationTypeMismatch: Account(#70154465182260) expected, got Fixnum(#70154423875840)
Both account_id and original_owner_id are set to be integers.
original_account_id is expecting an account object. you cannot set an id.
credit_record.original_owner = account
credit_record.account = account
or
credit_record.account_id = account.id
Please rename your association to the following
class CreditRecord < ActiveRecord::Base
belongs_to :original_owner, :foreign_key => "account_id", :class_name => "Account"
belongs_to :account
I'm not sure why you want to name your association account_id instead of just account in your CreditRecord class. The problem with this approach is when you have/will have nested resources like the following in your routes:
resources :accounts do
resources :credit_records
end
you will get a URL pattern as /accounts/:account_id/credit_records/:id/..., and your params hash will have account_id parameter in it.
Suggest updating your associations as follows as suggested by #vimsha in his answer.
class CreditRecord < ActiveRecord::Base
belongs_to :original_owner, :class_name => Account, :foreign_key => 'account_id'
belongs_to :account, :class_name => Account
end
This will allow you to assign account's id attribute through credit record object like:
# Set account's id
credit_record.account.id = 1
# Set original_owner's id
credit_record.original_owner.id = 2

Rails one-to-one relationship

I have the following:
class User < ActiveRecord::Base
has_one :car, :class_name => 'Car', :foreign_key => 'user_id'
class Car < ActiveRecord::Base
belongs_to :worker, :class_name => 'User', :foreign_key => 'user_id'
It is basically a one-to-one relationship between a user and a car.
What I want is for the User to be able to have one and only one car. That implies the fact that if he creates a car assigned to him, he won't be able to create the second.
How could this be done?
There are certainly a couple different ways of accomplishing this. I would suggest creating a composite key index on that table to ensure that the user_id is unique in the table. This will ensure that it will only be present once. In a migration, you could write something like this.
add_index(:cars, :worker_id, :unique => true)
The first argument is the table name (don't forget this is generally the pluralized version of the class name). The field name comes second. The unique true is what will prevent you from inserting an extra row.
Note: This is a database level constraint. If you hit this because validations didn't catch it, it will throw an error.
In addition to this solution, you will want to add a validation to the Car model itself.
validates_uniqueness_of :worker_id, message: "can not have more than one car"
You'll see this error come through with something like "Worker ID can not have more than one car". You will most likely want to customize the "Worker ID" section of this. Refer to this post for instructions on how to do that.
You certainly don't have to do the db constraint, but in case anyone else inserts into the DB, it's a good idea. Otherwise, you'll have "invalid" data as far as Rails is concerned.
Change the definition of the relationship slightly:
class User < ActiveRecord::Base
has_one :car
class Car < ActiveRecord::Base
belongs_to :worker, :class_name => 'User', :foreign_key => 'user_id'
And you'll establish what you're looking for. See: http://guides.rubyonrails.org/association_basics.html#the-has-one-association
why don't you just test before the user tries to add a car?
if worker.car
raise "sorry buddy, no car for you"
else
car = Car.create(user_id: worker.id)
end

Rails - application design for 2 user types

I am writing ruby on rails app, that will have 2 different types of users (let's say sellers and buyers). I was thinking about using single table inheritance, but ultimately I decided to crate 2 separate models (I believe it's better solution in my case).
The problem is when I try to create private message model (both sellers and buyers can contact each other). Typically I would just generate model called message with 3 fields (from_user_id to_user_id and content). This will not work in my case, because there might be 2 users with the same id (1 seller and 1 buyer).
I was thinking about using e-mail to identify sender and receiver, but e-mail is not my primary key, so I guess I won't be able to use it a foreign key in message model. Oh - btw, what is the best way to make sure that e-mails are unique in both sellers and buyers tables (in other words user can't join as a seller and buyer from one email)
Any ideas how I can elegantly solve my problem?
Why do you decided to not have a single User model? Considered all the issues caused by having these users in two separated tables I would have a User model and extend this model to have a Buyer model and a Seller model.
I think a buyer or a seller is still a user of your application, this resolves the problem of the message from a user to another too.
class User < ActiveRecord::Base
# Remember to add a "type" column in the users table
end
class Seller < User
end
class Buyer < User
end
The messages are now between users, no matter which kind of user.
What you are looking for is a polymorphic association. What this allows you to do is have a model that can belong to multiple other models through the same relationship by specifying the ID as well as the Class of the other object. For example, if buyer ID 3 sends a message to seller ID 5, your message table will end up with a row like:
sender_id = 3
sender_type = Buyer
receiver_id = 5
receiver_type = Seller
To accomplish this in active record, your models will look like the following:
class Message < ActiveRecord::Base
belongs_to :sender, :polymorphic => true
belongs_to :receiver, :polymorphic => true
end
class Buyer < ActiveRecord::Base
has_many :sent_messages, :class_name => "Message", :as => :sender
has_many :received_messages, :class_name => "Message", :as => :receiver
end
class Seller < ActiveRecord::Base
has_many :sent_messages, :class_name => "Message", :as => :sender
has_many :received_messages, :class_name => "Message", :as => :receiver
end

Beta Invite Codes Rails

I've seen some great resources for creating invitation systems where the app sends an email invitation with a link to the invited user's email, like devise_invitable.
What I'm trying to figure out is how to generate a bunch of invite codes so that I can give them out to specific people, and then they can sign up with that invite code. I have some ideas of what I would do but I'm wondering if anyone's every come across this before and has some tried and true methods.
I'm using devise for authentication by the way.
Any help is much appreciated.
You could always create an InviteCode model that contains a randomly generated redeemable code that can be issued on demand and validated at a later point in time.
For example:
class User < ActiveRecord::Base
has_one :invite_code_used,
:class_name => 'InviteCode',
:foreign_key => 'user_redeemer_id'
has_many :invite_codes,
:foreign_key => 'user_creator_id'
end
class InviteCode < ActiveRecord::Base
belongs_to :user_creator,
:class_name => 'User',
:foreign_key => 'user_creator_id'
belongs_to :user_redeemer,
:class_name => 'User',
:foreign_key => 'user_redeemer_id'
end
You'd create a randomly generated string to use as the invite code, presumably somewhere like before_validation to ensure it's populated before saving. When the code is redeemed, link the code to the user that was created so you can see who actually claimed it.
Creating an invite code for a user is as simple as something like this:
#invite_code = #user.invite_codes.create(:email => 'someone#example.com')
You can add some validations on the creation of an InviteCode to ensure that a given user hasn't created more than they should've and any other business logic you might require.

Rails multiple roles defined in relationship with a third party

I am building a small app which has classes User, Student, Tutor, Meeting.
Each user can be tutor in one Meeting, but student in another meeting. I have been thinking about how to model these relationship.
Right now, I have a User model, a separate Participant model with an attribute Role = "tutor"/"student". Tutor and Student extend Participant using single-table inheritance, and belong to Meeting.
However, I wonder if this is a good design. (It seems to be unintuitive to me).
What would you do in my situation?
Thank you.
It is acceptable but there are other ways that are cleaner. You could design you Meeting model like this:
has_and_belongs_to_many :users, :as => :studens
belongs_to :tutor, :foreign_key => 'tutor_id', :class_name => 'User'
Your User Model:
has_and_belongs_to_many :meetings, :as => :meetings_taken
has_many :meetings_given, :foreign_key => 'tutor_id', :class_name => 'Meeting'
So you would only need two models.
// edit
For propose, accept, decline,.. I would create a Invitation Model user_id:integer (Invited User), meeting_id(Through this you know who is allowed to invite other people because Meeting belongs to the tutor), status:string (waiting, accepted, delicesed might be options) maybe explaination:text (When somebody delices).

Resources