Foreign key same as associated table? - ruby-on-rails

i have a cutom foreign key name (non association+_id) like so:
belongs_to :investment_advisor, :foreign_key => "investment_advisor"
This creates a problem because rails gets confused and doesnt know if im referring to the association or the foreign key. Is there any way i can rename the foreign key (without touching the database) to something else? Like a variable or something?

You could rename your association, for one:
belongs_to :investment_advisor_obj,
:foreign_key => "investment_advisor",
:class_name => "InvestmentAdvisor"
(or you could pick a less silly name)

Related

Rails Unconventional DB Structure, is this problematic for associations?

My company's old team leader had fairly little knowledge of Ruby on Rails and used weird convention for the db structure for associations.
Let's say I have a User model and a Role model, and that a user belongs to a role.
What I would consider typical:
rails g migration AddRoleToUsers role:references
# app/models/user.rb
belongs_to :role
# app/models/role.rb
has_many :users
But I can clearly see that something else has happened.
Whenever I User.new, I get something like:
#<User stuffs, role_id: nil>
In the models I've got
# app/models/user.rb
belongs_to :role, :class_name => 'Role', :foreign_key => :role_id
# app/models/role.rb
has_many :users
This pattern litters a good part of our application. I can tell that these columns are index, but don't actually have a foreign keys.
First question, is this problematic? To me, this implies referential integrity issues.
Second question, how can I add a foreign key after the fact and preserve existing data?
I'm using a gem called data-migration, which I hope can help me preserve the information.
This is just a verbose way of writing what Rails will do automatically by convention.
In the User.role relationship, this:
belongs_to :role, :class_name => 'Role', :foreign_key => :role_id
is equivalent to this:
belongs_to :role
Rails can infer the class_name and foreign_key based on the name of the relationship. It's just a redundancy that won't hurt in this case.
The foreign_key is actually the name of the field that's used to store the id value for the relationship, it's not a database foreign key at all.
You can add a database foreign key for these relationships by creating a migration or each table that you want to update. There's a great answer for that in Adding foreign key to a rails model that gives the step-by-step instructions to do it.

Rails foreign key other than id

I have an ActiveRecord named Ad, and it has column id and server_id. They are both unique. id is given by Rails, but what's meaningful here is server_id.
Then I need to create another ActiveRecord named Bid which has 1 to 1 relationship with Ad. Bid has a key ad_id which refers to Ad.server_id.
I know that I should specify Ad has_one Bid and Bid belongs_to Ad, and specify foreign key name through foreign_key: "ad_id". What's troubling me here is I can only find out how to let Bid.ad_id refer to Ad.id while I want it refers to Ad.server_id.
Can anybody show me how to achieve this? Thanks!
User primary key
Bid.rb
belongs_to :ad, :foreign_key => :ad_id, :primary_key => :server_id
Ad.rb
has_one :bid, :foreign_key => :ad_id, :primary_key => :server_id
foregin_key option is not needed here but adding to make the difference between it and primary_key clear.
Have you tried using 'references' when generating your model.
i.e.
rails generate model Advertisement bid:references

Rails belongs_to returns nil class

I am trying to link two tables to each other
class Musers < ActiveRecord::Base
# Email
# sid (student_id:integer)
# isyk: boolean
belongs_to :user, :foreign_key => "smail"
end
class Users < ActiveRecord::Base
belongs_to :muser, :foreign_key => "email"
end
But,
#user = Users.first
#user.muser returns nil
By saying :foreign_key => "smail" you are telling rails that the Muser column smail points to the User model's foreign key. This is most likely not the case.
Assuming that the primary key of the User models is called id, you should a user_id field to Muser, and change belongs_to :user, :foreign_key => "smail" into:
belongs_to :user
On the User model you can define the reverse relation using:
has_one :muser
Also, to follow rails model naming conventions, you should rename Users to User and Musers to Muser.
You should read more about belongs_to and has_one.
If, on the other hand, the User model in fact uses email for it's primary key, I would strongly advise you to change that and add an auto-incrementing primary key instead. As a rule of thumb, the primary key should be chosen such that it never changes. If it does change, all foreign keys pointing to that primary key will have to change as well.
You should only use a non auto-incrementing primary key if you have a specific reason for doing so.
More information on choosing a primary key: How to choose my primary key?
Well you can't just tell rails the type of association, you actually have to set the association to an instance of that class. For example, making a new muser will not automatically assign a user as the belongs_to. You could do something like
u = User.new
u.muser = Muser.first
u.save
However, I'm not sure what you are trying to accomplish with a belongs_to - belongs_to relationship, but you should know that you have to do more than just tell rails it exists.

is it possible to customize foreign key to use a regex

We have a simple item and order model.
orders(url)
items(title, orders_count)
Where "url" can be any URL from the web for e.g. http://amzn.to/aCKiXO. What we would like to do is that if the user enters "/items/7" for the "url" then have it behave like a foreign key. So something like:
class Order < ActiveRecord::Base
belongs_to :item, :foreign_key => :url, :regex => /items/n,
:counter_cache => true
end
class Item < ActiveRecord::Base
has_many :orders, :foreign_key => :url, :regex => /items/n,
:dependent => :destroy
end
Is this possible? We're on Rails 2.3.8, Ruby 1.9.3 and on Postgresql 9.1
No, it isn't possible to add a foreign key constraint that does a regular expression match - or anything except simple equality. See the PostgreSQL documentation on constraints.
What you can do is any of:
Write a constraint trigger in PL/PgSQL to enforce the constraint you want;
Split out the part you want to add a constraint on using a regexp in the application, and define a foreign key constraint on a column containing only that part; or
Use a BEFORE INSERT OR UPDATE ... FOR EACH ROW trigger to split the part of interest out in PL/PgSQL when the row is inserted and add the part of interest to a foreign key column that contains only that part. The app doesn't need to know about the duplication since the DB is taking care of it behind the scenes.

conflict between attribute name and foreign key name

I am wondering if it is possible to have the following situation: I have a person object that has both an attribute called email and a foreign key called email which is realized as a has_many relationship. The latter is supposed to contain not only the primary email but also secondary ones. Would this cause conflict when I invoke #person.email? What would be the standard way to work around this? Thanks.
Create a secound field that could be used as a foreign key and then in the associated model add :foreign_key => 'your_foreign_key' as aparameter to the existing association like this:
has_many :email_addresses, :class_name => 'ClassName', :foreign_key => 'your_foreign_key'
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html <-- Documentation about that.

Resources