model has two attributes that belong to another model - ruby-on-rails-3

I have a model as follows:
Greeting
belongs_to :icon
belongs_to :icon, :foreign_key => :user_icon
I need to save the icon_id and also the user_icon id in the case I don't have a registered user.
Is this correct? Will I be able to access the icon by doing the following:
#greeting.icon.name
#greeting.user_icon.name
I want to improve this question so let me explain it better:
I want to save two objects from the same model in another model.
So Greeting belongs to Icon but I will have two fields in the Greetings table for foreign keys from the Icons table but labeled differently.
I call one foreign key attribute icon_id and the other user_icon_id.
To do this is the following correct:
Greeting
belongs_to :icon
belongs_to :icon, foreign_key => :user_icon_id

Almost correct, you need something like this:
belongs_to :icon
belongs_to :user_icon, :class_name => "Icon", foreign_key => :user_icon_id
If you change the name of the field in a has_one, has_many or belongs_to association in such a way that Rails can't convert it into a model name, you need to tell Rails which model you actually mean, hence the :class_name.

Nope. You need
belongs_to :user_icon, :foreign_key => :user_icon
If you want to have a greeting.user_icon accessor using the foreign key user icon in your database.

Related

Unique Association :through

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.

Relationships in Model Ruby on Rails

I have a View called View_CrossReference in Sybase. I want to create Model for this view.
This table has a column called Answer.
I have an another table and model called SurveyXref. In this table i have a column
called Answer_No.
I want to create a relationship between these models and get the data from Answer column from View_CrossReference and display into my grid in SurveyXref page.
IN view_crossreference model
has_one :survey_xrefs, :primary_key => :answer, :foreign_key =>
:answer_no
In survey_xrefs model
belongs_to :view_crossreference, :primary_key => :answer ,
:foreign_key => :answer_no
now simply in controller u can access
v.view_crossreference.answer
Without "Model", means you have created table via stand alone migration.
Could you please show me your code for better understanding?

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 - two foreign keys on one model both refer to same model

I'm fairly new to ActiveRecord associations. I'm sketching out an application that tracks who owes each other money among a set of users. An Expense model and a User model seem like natural choices, I'm just not sure how to define the relationship between the two. For example, I want to track the creditor ("owner") and the debtor of each expense, but that's really just two foreign keys that go back to User. In addition, each user can have multiple expenses (both as creditor and debtor) My best guess for the associations thus far is something like:
class Expense
# belongs_to or has_one here?
# Not sure about class => User syntax:
# need to alias to foreign keys that reference the same model
belongs_to :creditor, :class => User
belongs_to :debtor, :class => User
class User
# has_many expenses defines a creditor relationship (user owns expense)
# how to define debtor relationship? (belongs_to...?)
has_and_belongs_to_many :expenses
I've read the Rails guide on associations but I'm still fairly lost on foreign keys and join tables. Any input is much appreciated!
So this is definately not a has_and_belongs_to_many thats for many-to-many relationships. You just need to use a couple has_many relationships. I think it should end up looking like this:
Edit: oops I fudged that a bit that up sorry let me have another go:
class Expense
# make sure expense table has 'creditor_id' and 'debtor_id' rows
belongs_to :creditor, :class_name => "User", :foreign_key => :creditor_id
belongs_to :debtor, :class_name => "User", :foreign_key => :debtor_id
class User
has_many :debts, :class_name => "Expense", :foreign_key => :debtor_id
has_many :credits, :class_name => "Expense", :foreign_key => :creditor_id
The other answers tell you what you need to do, but it can be kind of confusing to people who are new to Rails, as I am, to piece all these things together, so here is a complete solution, including both Migrations and Models.
Also, as a side note: I prefer Loans, Lender and Borrower to Expense, Creditor and Debtor, or Debt, Creditor and Debtor. Mostly because Expense is ambiguous and Debt is too similar to Debtor. But it's not that important; just do what makes sense to you, since you will be maintaing your code.
Migrations
class CreateLoans < ActiveRecord::Migration
create_table :loans do |t|
def up
t.references :lender
t.references :borrower
end
end
end
Here you are specifying that there are two columns in this table that will be referred to as :lender and :borrower and which hold references to another table. Rails will actually create columns called 'lender_id' and 'borrower_id' for you. In our case they will each reference rows in the Users table, but we specify that in the models, not in the migrations.
Models
class Loan < ActiveRecord::Base
belongs_to :lender, class_name => 'User'
belongs_to :borrower, class_name => 'User'
end
Here you are creating a property on the Loan model named :lender, then specifying that this property is related to the User class. Rails, seeing the 'belongs_to', will look for a column in the loans table called 'lender_id', which we defined above, and use that to store the foreign key. Then you're doing the exact same thing for the borrower.
This will allow you to access your Lender and Borrower, both instances of the User model, through an instance of the Loan model, like this:
#loan.lender # Returns an instance of the User model
#loan.borrower.first_name # Returns a string, as you would expect
As a side note: the 'belongs_to' nomenclature makes decent sense in this case, but can be kind of confusing elsewhere. Just remember that it is always used on whichever thing contains the foreign key.
class User < ActiveRecord::Base
has_many :loans_as_lender, :class_name => 'Loan', :foreign_key => 'lender_id'
has_many :loans_as_borrower, :class_name => 'Loan', :foreign_key => 'borrower_id'
end
Here you are creating a property on the User model named :loans_as_lender, specifying that this property is related to the Loan model, and that the foreign key on the Loan model which relates it to this property is called 'lender_id'. Then you are doing the same thing for :loans_as_borrower.
This allows you to get all the loans where a User is the lender or borrower, like this:
#address.loans_as_lender
#address.loans_as_borrower
Doing either of these will return an array of instances of the Loan model.
If your expense migration looks like this:
create_table :expenses do |t|
t.integer :creditor_id, :null => false
t.integer :debtor_id, :null => false
# other attributes here
end
then your Expense model is sufficient. If you take a look at the documentation for belongs_to, you'll see that it will correctly infer the foreign keys into the user table:
:foreign_key
Specify the foreign key used for the association. By default this is guessed to be the name of the association with an “_id” suffix. So
a class that defines a belongs_to :person association will use
“person_id” as the default :foreign_key. Similarly, belongs_to
:favorite_person, :class_name => "Person" will use a foreign key of
“favorite_person_id”.
So you don't need to explicitly specify a foreign key here. If you use other naming conventions for the ids in your expenses model, then you need to explicitly specify them in your associations.
For your User model, you don't have a many_to_many relationship with expenses - an expense always belongs to exactly one debtor and exactly one creditor. So all you need is two has_many associations:
has_many :debts, :class_name => 'Expense', :foreign_key => :debtor_id
has_many :credits :class_name => 'Expense', :foregin_key => :creditor_id

I need to specify a field name different than the table for association

Given I have an Artifact model and a User model: I would like to define two Artifact fields, opened_by and assigned_to, who values are User ids and inherit all of the proper association methods.
What is the proper belongs_to or has_one or has_many options I should set?
The goal is to be able to reference the user's name through the statement hld.assiged_to.name where hld is an artifact.
Thanks for the help. I've gotten myself confused with terminology with all of the reading i've done on the problem.
The following is what I determined was correct.
class Artifact < ActiveRecord::Base
belongs_to :project
belongs_to :opened_by, :class_name => 'User'
belongs_to :assigned_to, :class_name
=> 'User'
The first argument in the belongs_to specifies the field to reference. The second indicates the model/class to use as the reference.