I have two models Artist and Painting.
I added the following migration and executed rake db:migrate
class AddArtistReferenceToPaintings < ActiveRecord::Migration
self.up do
change_table :paintings do |t|
t.references :artist
end
end
end
This doesn't change anything in the database. What am I doing wrong?
Seems correct .
Did you already run this migration and added this latter ? If yes then create new one OR delete version from schema_migrations .
Way :
To add a foreign key column
change_table(:suppliers) do |t|
t.references :company
end
It creates a company_id(integer) column
To add a polymorphic foreign key column
change_table(:suppliers) do |t|
t.belongs_to :company, :polymorphic => true
end
It creates company_type(varchar) and company_id(integer) columns .
For further detail refer the link.
Try
t.belongs_to :artist
instead
t.references :artist
But your variant should work too, if you test in irb console. Run 'reload' to update.
Related
I have the following code in my Rails 'seeds.rb' file:
acondigitaladdresslineone = Addressline.create!(address_id: acondigitaladdress.id, address: "Sørkedalsveien 273", address_line_position: 0)
The 'Address' model has a one-to-many relation with the 'Addressline' model, and the respective 'belongs_to' and 'has_many' declarations are properly in place. Here is the content of the migration files:
class CreateAddresses < ActiveRecord::Migration[5.0]
def change
create_table :addresses do |t|
t.references :towncity, foreign_key: true
t.references :stateregion, foreign_key: true, null: true
t.references :postalcode, foreign_key: true
t.timestamps
end
end
end
class CreateAddresslines < ActiveRecord::Migration[5.0]
def change
create_table :addresslines do |t|
t.references :address, foreign_key: true
t.string :address
t.integer :address_line_position
t.timestamps
end
end
end
When I run the Rails Console, I receive the following error, which refers to the "acondigitaladdresslineone = ..." line of code:
ActiveRecord::AssociationTypeMismatch: Address(#8269560) expected, got String(#6922340)
I corrected the error by making the following changes:
# From the 'CreateAddresslines' migration file
# Original code
t.string :address
# Revised code
t.string :address_name
# From the 'acondigitaladdresslineone' variable declaration line
# Original code
address: "Sørkedalsveien 273"
# Revised code
address_name: "Sørkedalsveien 273"
I suspect the cause of the error possibly is due the underlying database's (in this case SQLite) inability to disambiguate the same field name based upon datatype. For example, in the original version of the 'CreateAddresslines' migration file, SQLlite raises an error as a result of these two declarations:
t.references :address, foreign_key: true
t.string :address
It is easy to overlook the obvious when entangled in coding. Clearly, a relational database table cannot have two or more columns with the same name. I am unaware of any relational database management system having a capability to disambiguate same-named table columns based upon differences in their datatypes.
I need a sanity check. Is this a reasonable assumption why the 'AssociationTypeMismatch' error was raised?
Thank you.
t.references :address will create the column address_id so there should be no conflict with t.string :address on the DB level.
The problem occurs in ActiveRecord when accessors and associations are declared.
ActiveRecord reads the schema from the database and uses it to create attributes and accessor methods in your models for each column. This happens before any of the code in the class declaration block is evaluated.
When you then create an association you are overwriting the #address and #address= methods created for the string attribute.
class Addressline
belongs_to :address
end
Which is why when you do:
Addressline.new(address: 'Foo')
You get a type error since the #address= setter method is setting address_id and expects an Address instance.
The solution is as you might have surmised is to not name other columns the same thing as your associations. Just rename the column:
class FixColumnName < ActiveRecord::Migration
def self.change
# call it whatever you want, but not address!
rename_column :addresslines, :address, :value
end
end
I am trying to add seller_id to my items model in a migration by doing the following:
rails g model Item title:string description:text price:bigint status:integer published_date:datetime seller:belongs_to
This didn't work of course...
ultimately I want to see seller_id in my items table, which relates the item model to the user model.
Presently my migration looks like this:
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.string :title
t.text :description
t.bigint :price
t.integer :status
t.datetime :published_date
t.belongs_to :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
How can I modify this migration to create a foreign key "seller_id" that relates to the user model.
How can I auto generate a migration that includes edits from 1., from the console? I.E modify the rails g model ... to generate the migration I need.
Huge Thanks!
Just explicitly define what you want in the migration file and add the necessary relation to your model, instead of t.belongs_to you could just use:
t.integer :seller_id, index: true, foreign_key: true
and in your models you could go about this a few ways, if you also want reference your relation as seller on item instances then in the Item class make the relation:
belongs_to :seller, class_name: 'User'
and in the User class:
has_many :items, foreign_key: :seller_id
or if you want to reference it as user from the items then:
belongs_to :user, foreign_key: :seller_id
In terms of editing the generator, that is the default way that a model generator works and in my opinion I like to keep the defaults the way they are. However I do recommend creating your own rails generators or your own rake tasks for when you want to create some custom / special case stuff. For looking at creating your own generator I would point you to the ruby on rails official guide for creating generators to get you started: http://guides.rubyonrails.org/generators.html
Inside your migration you can use
t.belongs_to :seller, foreign_key: {to_table: :users}
If you don't want it to be specifically called seller_id then what you have is enough. Once you run your migration using rake db:migrate you will see the actual table structure in your db/schema.rb file with a foreign key user_id
You can simply edit the generated migration file in your favorite text editor to edit the migration before running rake db:migrate
I wan to make simple has_many and belongs_to relation between my models.
I have User model and Quote model. And each quote belongs to user and evry user has many quotes.
I've studied this: http://guides.rubyonrails.org/association_basics.html
But I still don't know what about foreign key. Does Rails do it automatically in background (when I add has_many and belongs_to) or should I add manually migration with user_id column added to Quotes table?
Should I have user_id column in my db_schema?
The foreign keys should be defined in your migration. If you use the generator, Rails will generate a migration, which maybe looks like the following:
class CreateQuotes < ActiveRecord::Migration
def change
create_table :quotes do |t|
t.string :title, null: false
t.text :content, null: false
t.references :user
t.timestamps
end
end
end
The statement t.references :user will generate your foreign key column, which is called user_id in this case.
Here is a quote from the Rails Guides:
Using t.integer :supplier_id makes the foreign key naming obvious and explicit. In current versions of Rails, you can abstract away this implementation detail by using t.references :supplier instead.
I created a many-to-many relationship in rails, here's my models and migrations
class Channel < ActiveRecord::Base
has_and_belongs_to_many :packages
validates_presence_of :name
end
class Package < ActiveRecord::Base
has_and_belongs_to_many :channels
validates_presence_of :name
end
class CreateChannelsPackages < ActiveRecord::Migration
def change
create_table :channels_packages, :id => false do |t|
t.references :channel
t.references :package
t.timestamps
end
add_index :channels_packages, :channel_id
add_index :channels_packages, :package_id
end
end
Then i have a multiple select, but when i try to save i get this error
SQLite3::ConstraintException: constraint failed: INSERT INTO "channels_packages" ("package_id", "channel_id") VALUES (1, 1)
I tried to remove the indexes from the migration but it didn't solve it, did somebody else have this problem?
Btw i'm using Rails 3.2.6 and sqlite3 1.3.6
I think gabrielhilal's answer is not quite correct: use of extra attributes in the join table is deprecated, thus you need to remove the timestamp in your migration, then it should work just fine with the has_and_belongs_to_many wich itself is not deprecated.
If you do need additional attributes in your join table, though, has_many :through is the way to go.
There is also another question with good answers on this topic:
Rails migration for has_and_belongs_to_many join table
I don't know if it is the reason of your problem, but the has_and_belongs_to_many association is deprecated.
According to the Rails Guide:
The use of extra attributes on the join table in a has_and_belongs_to_many association is deprecated. If you require this sort of complex behavior on the table that joins two models in a many-to-many relationship, you should use a has_many :through association instead of has_and_belongs_to_many.
I know that you are not adding any extra attribute to the join table, but try changing your migration to the below, which I think is the default:
class CreateChannelPackageJoinTable < ActiveRecord::Migration
def change
create_table :channels_packages, :id => false do |t|
t.integer :channel_id
t.integer :package_id
t.timestamps
end
end
end
I have the following Rails migration which works perfectly (irrelevant pieces removed):
create_table :comments do |t|
t.text :body
t.references :post
end
Now I'd like to add an author column to my comments table (which is the userid of a user), but I have no idea how to do it (I'm tempted to just write the MySql-specific syntax using an execute).
I've been looking at add_column here which doesn't mention references. I've actually found TableDefinition#references but I have no idea how to use it with an add_column statement.
Is this possible? Also, is it true that, for MySql, the "references" functionality does not actually establish relationships between the tables?
While it's too late to get any points out of this, I thought I'd post the best way for posterity :)
use change_table instead of create_table to add columns to a table that already exists, with all the TableDefinition goodness:
self.up do
change_table :comments do |t|
t.references :author
end
end
This might seem trivial, but other gems like Devise make heavy use of their own custom table definitions, and this way you can still use them.
add_reference :table_name, :reference, index: true
Finally got it
add_column :locations, :state_id , :integer, :references => "states"
First, do:
script/generate migration AddAuthorIdToComments
Open the generated file and add this line:
add_column :comments, :author_id, :integer
Then in your model files:
class User < ActiveRecord::Base
has_many :comments, :foreign_key => "author_id"
end
class Comment
belongs_to :author, :class_name => User
end
It's been a while since I've looked at this, but last I checked migrations don't support creating foreign keys. Fortunately, however, there is a plug-in for it. I've used this and it works well.
You could add the column by add_column(:table, :column_name, :type, :options) in a new Migration.