Create SQLite 3 table with foreign key constraint via ActiveRecord migration - activerecord

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?

Related

Add column to schema before created_at column

I'm trying to add a column to my table.
Here is my migration file:
class AddEmail < ActiveRecord::Migration
def change
add_column :apps, :email, :string, after: :website
end
end
However, when I run it, the newly created email column goes all the way to the last column after updated_at:
ActiveRecord::Schema.define(version: 20141217210326) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "apps", force: true do |t|
t.string "name"
t.string "iTunes"
t.string "website"
t.datetime "created_at"
t.datetime "updated_at"
t.string "email"
end
end
What I want is for the new email column to go in between the website and created_at column. How do I do that?
Postgres doesn't support the ordering of columns in tables. If you don't have any code in production, just alter the original migration that creates the apps table.

has_many or join - what's the 'rails way' to use my table?

I have a database that keeps track of accidents. Each accident can have multiple causes. Each cause has a friendly name in a 3rd table. What's the 'rails way' to create this association?
Here's what I have:
create_table "accidents", force: true do |t|
t.text "notes"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "causes", force: true do |t|
t.integer "accident_id"
t.integer "cause_name_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "cause_names", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
CauseName.create :name => "DUI"
CauseName.create :name => "Speeding"
Accident:
class Accident ActiveRecord::Base
has_many :causes
end
Causes:
class Cause < ActiveRecord::Base
belongs_to :accidents
has_one :cause_name
end
cause names:
class CauseName < ActiveRecord::Base
belongs_to :causes
end
It seems like to be properly "ORM"'d, I'd use it like this:
Accident.causes.first.cause_name.name #speeding
a = CauseName.find(1)
Accident.causes.first.cause_name = a #set and saved successfully
I've been trying a variety of things, but I can't seem to get my associations to work the way I'd expect. I know I'm not using it right.
I'm very new to rails and activerecord, and horrible with databases... the schema I'm working with was designed by our dba who will be doing reporting on the table, but knows nothing about Ruby or ActiveRecord.
What's the best approach in my situation? Am I even using this thing right?
I think you have your belongs_to and has_one methods placed incorrectly in your Cause - CauseName association.
Quoting the official guide:
If you want to set up a one-to-one relationship between two models,
you'll need to add belongs_to to one, and has_one to the other. How do
you know which is which?
The distinction is in where you place the foreign key (it goes on the
table for the class declaring the belongs_to association), but you
should give some thought to the actual meaning of the data as well.
The has_one relationship says that one of something is yours - that
is, that something points back to you.
So, in your case, it should be like this:
class CauseName < ActiveRecord::Base
has_one :cause # Note that I have changed :causes to singular too
end
class Cause < ActiveRecord::Base
belongs_to :accident # <- Singularized too
belongs_to :cause_name
end
In your case, I'd suggest not splitting causes into two tables. Just cram name into causes table and call it a day.
Then you can easily query like #accident.causes.first.name

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)

how to create migration script with foreign key

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'

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.

Resources