I am using Ruby 1.8.7 and Rails 2.3.8 and I have the following root resource:
class PointOfInterest < ActiveRecord::Base
set_primary_key "Id"
set_table_name "POI"
has_many :attributes, :foreign_key => 'POIId'
end
The point of interest can have several attributes:
class Attribute < ActiveRecord::Base
set_primary_key "Id"
set_table_name "Attribute"
belongs_to :point_of_interest, :foreign_key => 'POIId'
has_one :multimedia, :foreign_key => 'Id', :primary_key => 'Value'
end
The attribute class may have media associated with it:
class Multimedia < ActiveRecord::Base
set_primary_key "Id"
set_table_name "Multimedia"
end
I am trying to insert a point of interest in my database like so:
poi = PointOfInterest.new
attr = poi.attributes.new
attr.SomeAttribute = 1
attr.build_multimedia(:content => 'test')
poi.save
This is properly persisting both the root (PointOfInterest) and the Multimedia record. The Attribute, however, is not being properly persisted. While the foreign key to the point of interest is properly set (POIId), the foreign key to the Multimedia record remains null.
Any clue as to why this is very much appreciated!
Thanks!
Your relationship / foreign key are set at cross purposes.
If Attribute has_one Multimedia, then you need the Multimedia model to declare belongs_to :attribute, and the Multimedia table to contain a foreign key for Attribute.
I'm guessing that you can't change your database schema (otherwise, I'd have to ask why you're using non-Rails-standard table and key names); in which case you want to switch the sense of the relation. Make Attribute belongs_to :multimedia, and Multimedia has_one :attribute. Then the Multimedia FK in the Attribute table is pointing in the right direction.
Related
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.
Are foreign keys explicitly required in relationships between two models in Mongoid? For example.
class User
include Mongoid::Document
has_many :posts
end
class Post
include Mongoid::Document
belongs_to :user
# Is this necessary below?
field :user_id, type: Integer
end
The documents on Mongoid's site don't indicate any declarations of fields when discussing relations which is why I ask.
No, generally separate foreign key field declarations are not needed. Mongoid will implicitly create the user_id field on any documents that need it. It follows the same foreign key naming conventions as ActiveRecord.
If those conventions aren't right for your model (e.g. if you have two associations to the same class) then you can override the foreign key name. e.g.
belongs_to :user, foreign_key: :friend_id
Again this is pretty much the same as ActiveRecord (but without the migrations of course).
Model region.rb:
class Region
...
field :title
has_many :users
...
Model user.rb:
class User
...
belongs_to :reg, class_name: "Region", foreign_key: :reg_id
...
You can now use region for user as follows user.reg, for example:
= user.reg.title
I have the following tables
keyword
keyword_id - PK
description
status_id - FK
keyword_status
status_id - PK
description
Trying to model them in AR and when attempting to save in my test it's not saving the status ID in keyword. They are mapped as such:
class Keyword < ActiveRecord::Base
self.table_name = :keyword
self.primary_key = :KEYWORD_ID
attr_writer :description
attr_writer :keyword_status
has_one :keyword_status, foreign_key: :STATUS_ID
end
class KeywordStatus < ActiveRecord::Base
self.table_name = :keyword_status
self.primary_key = :STATUS_ID
end
and the code where it breaks (keyword status is populated by a fixture)
keyword = Keyword.new
keyword.description = "keyword#{n}"
keyword.keyword_status = KeywordStatus.first
keyword.save
When keyword.save is called i get cannot insert NULL into 'STATUS_ID' on table Keyword
NOTE: I cannot change any of the DDL
As dstarh said, the foreign key association is backwards. In your models you should only need:
class Keyword < ActiveRecord::Base
has_one :keyword_status
end
class KeywordStatus < ActiveRecord::Base
belongs_to :keyword, :foreign_key => "status_id"
end
For the association to work. Also, setting the KeywordStatus object up with a fixture before creating the associated object is a bit odd but will work if that is the behavior you need. Also, why not just use the foreign key keyword_id and let rails handle it for you?
Update if you want to use keyword_id instead of status_id as the foreign key:
the tables will be as such:
keyword
id - PK
description
keyword_status
id - PK
keyword_id - FK
description
And your models:
class Keyword < ActiveRecord::Base
has_one :keyword_status
end
class KeywordStatus < ActiveRecord::Base
belongs_to :keyword
end
Hope this helps!
Update 2: Given the tables cannot change the association has to be a bit backwards. I would recommend:
class Keyword < ActiveRecord::Base
belongs_to :keyword_status
end
class KeywordStatus < ActiveRecord::Base
has_many :keywords, :foreign_key => "status_id"
end
I used a has many as the association since from what has been said it looks like a keyword can share a status that another keyword has. This also means that you will have to do something like:
KeywordStatus.first.keywords = KeywordStatus.first.keywords.push(keyword)
KeywordStatus.save
instead of:
keyword.keyword_status = KeywordStatus.first
Which operates in the opposite direction than you want. As you can see this can get pretty confusing so if at all possible i would suggest writing a migration to change your tables (this can be done for tables that have existing data if that is the problem). Again I hope this helps!
You got the direction wrong. It should be keyword belongs_to status. The general rule is that the model that has the foreign key column belongs to the other model.
I have a model called "EmployeeRecord" and it has a field called username, There is another model called "Employee" with a field called username.
I want to create an association between the 2 models so when I do:
record = EmployeeRecord.find(1)
record.employee // returns Employee instance
I was thinking I'd just need to do this, but apparently it doesn't work:
class EmployeeRecord < ActiveRecord::Base
has_one :employee, :foreign_key: username
end
Assume I can't add an employee_id field to EmployeeRecord. I scoured the Rails tutorials.. and recall wanting to know how to do this months ago.. but those dang Rails tutorials glided over this.. I remember.. it made me very very angry hehe
Any idea?
You'll also need to specify the primary_key used for the association, or else it's defaulted to "id". Your statement actually says "Search for a field username in table employee that is equal to my id field". What you actually want is "Search for a field username in table employee that is equal to my username field"
This should do the trick :
class EmployeeRecord < ActiveRecord::Base
has_one :employee, :foreign_key => username, :primary_key => :username
end
But hey... Why don't you use ids?
Add the foreign key option in the belongs_to method in your Employee model.
class Employee < ActiveRecord::Base
belongs_to :employee_record, foreign_key: username
end
The has_one or has_many is the parent, so it doesn't store the foreign key value/column. That's what the child does that has the belong_to side of the relationship.
I am using an existing database with a rails app.
I can't change the table or column names.
Lets say table one is "invoices" and table 2 is "orders"
they both have a primary key that is called the same thing, lets say "order_id"
invoices can find its order by looking at the primary key "order_id" in the orders table.
Vice versa for an order finding its invoice.
Invoices can have but not always have one order (you might be invoiced for something besides an order, like a "work_order" which would be found by looking for the "order_id" in the primary key position of the "work_orders" table. So invoices might have a work_order or an order.
orders always has an invoice
work_orders always has an invoice
Im trying to figure out the classes in the models.
Do you set the primary and foreign keys to the same thing? What about belongs_to? The way this DB is set up, nothing really belongs to anything, they just reference each other by this same value "order_id". Would it be like this?
class Invoice < ActiveRecord::Base
set_primary_key(:order_id)
set_foreign_key(:order_id)
end
-- snip --
class Order < ActiveRecord::Base
set_primary_key(:order_id)
set_foreign_key(:order_id)
end
... And the same for a work order.
class WorkOrder < ActiveRecord::Base
set_primary_key(:order_id)
set_foreign_key(:order_id)
end
Is this correct? It seems to trashy of a way to do it but this DB is terrible.
What about all the belongs_to stuff?
Let me know if I have left anything out.
Thanks!
I believe the answer could be:
class Order < ActiveRecord::Base
set_primary_key(:order_id)
belongs_to :invoice, :foreign_key => :order_id
end
class WorkOrder < ActiveRecord::Base
set_primary_key(:order_id)
belongs_to :invoice, :foreign_key => :order_id
end
class Invoice < ActiveRecord::Base
set_primary_key(:order_id)
has_one :work_order
has_one :order
end
Although I'm not really sure your primary key can also be a foreign key (I'm new to Rails too)