how to create migration script with foreign key - activerecord

I want to create tables with foreign key through my migration script.
create_table :posts do |t|
t.string :title
end
create_table :comments do |t|
t.references :post
end
after rake db:migrate, comments was not referred by post through id.
How to create this in rails-2.2.3?

You can create migration as normal table schema and use :primary_key option for belongs_to for broader support of legacy schemas and those using a separate foreign key:
belongs_to :posts, :foreign_key => 'post_id'

Related

avoiding destroy with foreign key

I'm new in Ruby on Rails. I don't understand how rails behave using foreign Key, I've researched it for some days but I didn't get the answer.
Simple sample:
I created two tables:
class CreatePosts < ActiveRecord::Migration
def change
create_table :posts do |t|
t.string :title
t.text :content
t.timestamps null: false
end
end
end
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.string :author
t.text :content
t.references :post, index: true, foreign_key: true
t.timestamps null: false
end
end
end
My models are:
class Post < ActiveRecord::Base
has_many :comments
end
class Comments < ActiveRecord::Base
belongs_to :post
end
My doubt is: As I have a Foreign Key in my table COMMENTS (.references :post, index: true, foreign_key: true) I guess that I wouldn't be able to destroy any post which has any COMMENTS associated to them, isn't it ?
I did as above but I am still able to destroy the posts, even when I have the comments associated. How can I treat it? What am I doing wrong?
Cheers
I'd refine your migrations to use the :on_delete options on your foreign keys. It can take one of those values : :nullify, :cascade, :restrict
From what I understand, you need to set this value to :restrict on your post_id column in your comments table, so that posts with associated comments can't be deleted.
Update:
Or, you could also directly set it on the association in your Post model:
has_many :comment, dependent: :restrict_With_error
Please take a look at:
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many -> See the Options: Section
From what i understand, you dont want to destroy a post if there are associated comments?
Why not put a if statement encapsulating the delete button for a post
So something like:
psudo code
if #post.comments exists
cant delete post
else
delete post
end

Create SQLite 3 table with foreign key constraint via ActiveRecord migration

Unlike MySQL and Postgres, SQLite doesn't support adding foreign key constraints to an existing table. One therefore can't create a foreign key constraint with add_foreign_key in an ActiveRecord migration.
However, as of 3.6.19, SQLite it does support including foreign key constraints in the CREATE TABLE statement, and it is possible to specify foreign_key: true when defining a reference column in a create_table migration:
class CreateChildren < ActiveRecord::Migration
def change
create_table :children do |t|
t.text :name
t.references :parent, foreign_key: true
end
end
end
However, when I look at the generated schema.rb, this appears to be ignored:
create_table "children", force: :cascade do |t|
t.text "name"
t.integer "parent_id"
end
Is there a technical reason this is impossible, or is it just a missing feature? Is there a workaround?

rails joins with module name

Here is how to join two models
User.where(:id => 1).joins(:posts)
but how to join two models with module/namspace
#schedules= Swimming::Classschedule.joins(:Swimming::Slot).where(:date => #date)
seems not working properly (with error message)
:Swimming is not a class/module
UPDATE
I have updated to
#schedules= Swimming::Classschedule.joins(:swimming_slots).where(:date => #date)
and I do have this table
create_table :swimming_classschedules do |t|
t.integer :slot_id
t.integer :coach_id
t.integer :level_id
t.string :note
t.timestamps
end
create_table :swimming_slots do |t|
t.string :date
t.string :start
t.string :end
t.timestamps
end
Howcome I got this error
Association named 'swimming_slots' was not found; perhaps you misspelled it?
update 2
add this line to Swimming::Classschedule module
belongs_to :swimming_slots ,:class_name=>'Swimming::Slot',:foreign_key => "slot_id"
and
change joins to
#schedules= Swimming::Classschedule.joins(:swimming_slots).where(:swimming_slots =>{:date => #date})
Now it works
you pass the association name to joins. for example, if you have an association like
has_many :swimming_slots, class_name: 'Swimming::Classschedule'
then you pass swimming_slots and rails will do the joins for you.
User.joins(:swimming_slots)
UPDATE:
if slot_id refers to a record in the swimming_slots table, you should have something like
belongs_to :slot, class_name: 'Swimming::Slot'
in your class schedule model. If you have that, you should be able to do
Swimming::Classschedule.joins(:slot)

ruby on rails : how to bring changes on database to model

I have update migrate script under db/migrate, and I did a
rake db:migrate
database script before update
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :firstname
t.string :lastname
t.string :account
t.timestamps
end
end
end
databse script after update
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :firstname
t.string :lastname
t.string :account
t.string :address
t.string :city
t.string :state
t.string :postcode
t.string :homephone
t.timestamps
end
end
end
after I dropped the old development.sqlite3 and old schema in schame.rb.
Say I added a few columns, but in the model these columns is missing.
But my model still is
class Student < ActiveRecord::Base
attr_accessible :firstname,:lastname,:account,
end
Is there a easy way I can bring the changes in new migrate script to model ?
If you want to allow for mass assignments of the other attributes, you can just add the keys to attr_accessible
class Student < ActiveRecord::Base
attr_accessible :firstname,:lastname,:account,:address, :city, :state, :postcode, :homephone
end
However, your model still has those attributes (or columns as you call them). You just can't do a mass assignment (like create or update_attributes) without making them attr_accessible first.
It looks like maybe you did rails generate migration which isn't meant to affect your model. I believe after you create your model everything afterward has to be done manually.
If you really want to effect changes to your database and model at the same time, your best bet might be to delete your migrations and model and do a rails generate scaffold (documentation) to create your entire scaffolding from scratch.
There are no problem to add the new columns manually in the model.

ActiveRecord and use of has_one & has_many

Consider this simple model, where a Project has one ProjectType and, naturally many Projects can be of that type.
So a Project has_one :project_type (called type) and a ProjectType has_many :projects.
In my migration I put (simplified for this example)
create_table :projects do |t|
t.string :name, :null => false
t.integer :type
end
create_table :project_types do |t|
t.string :name, :null => false
end
My Project class looks like this (again simplified for this example)
#!usr/bin/ruby
require 'active_record'
class Project < ActiveRecord::Base
has_one :type, :class_name => 'ProjectType'
end
And my ProjectType looks like
#!usr/bin/ruby
require 'active_record'
class ProjectType < ActiveRecord::Base
has_many :projects
end
I've written a simple Unit Test to check this works
#test creation of Projects and related objects.
def test_projects_and_etc
pt = ProjectType.create(:name => 'Test PT')
project = Project.create(:name => 'Test Project', :type => pt)
assert project.type.name == 'Test PT', "Wrong Project Type Name, expected 'Test PT' but got '#{project.type.name}'."
# clean up
project.destroy
pt.destroy
end
This test throws an error at the assert, saying
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: project_types.project_id: SELECT "project_types".* FROM "project_types" WHERE ("project_types".project_id = 1) LIMIT 1
The SQL seems to be assuming that there is a project_id field in the project_types table but that makes no sense if a ProjectType can be associated with many Projects. I suspect that my problem is something to do with my wanting to be able to refer to the ProjectType as project.type not project.project_type, but I am not sure how I'd fix this.
You need to use belongs_to instead of has_one on the project model.
You also need to add a project_type_id column on to the projects table.

Resources