I have two models: User and Listing.
I am trying to set up a one-to-many relationship between them via existing db columns.
class User < ApplicationRecord
has_many :listings
class Listing < ApplicationRecord
belongs_to :user, foreign_key: "user_id"
This is my migration:
class AddFkToListing < ActiveRecord::Migration[5.1]
def change
add_foreign_key :listings, :users, column: :user_id, primary_key: :user_id
end
end
But it created the foreign key in table users on column id.
Any idea how to do this properly?
Here is the DB schema:
create_table "listings", force: :cascade do |t|
t.integer "listing_id"
t.string "state"
t.integer "user_id"
t.string "title"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["listing_id"], name: "index_listings_on_listing_id", unique: true
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "remember_digest"
t.boolean "admin", default: false
t.string "activation_digest"
t.boolean "activated", default: false
t.datetime "activated_at"
t.string "reset_digest"
t.datetime "reset_sent_at"
t.string "request_token"
t.string "request_secret"
t.string "oauth_verifier"
t.string "oauth_token"
t.string "login_name"
t.integer "user_id"
t.index ["email"], name: "index_users_on_email", unique: true
end
Thank you so much!
Since you have a conventional foreign key field name (user_id in listings table), I believe this should work just fine for you:
class AddFkToListing < ActiveRecord::Migration[5.1]
def change
add_foreign_key :listings, :users
end
end
The syntax of add_foreign_key is:
first argument (:listings) - table which should contain foreign key
second argument (:users) - table which should be used for constraint
column: :user_id - specifies to which field of the listings table constraint should be applied
primary_key: - specifies the field of the users table to build a constraint
(see https://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_foreign_key)
The primary_key: :user_id part in your example actually refers (tries to) to non-existing user_id field in users table.
Related
I have a many-to-many association throught RoomsUsers model and in this model i have a role field, association works well but i can't access this field.
My schema looks like:
create_table "messages", force: :cascade do |t|
t.text "body"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "room_id"
end
create_table "rooms", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "rooms_user_id"
end
create_table "rooms_users", force: :cascade do |t|
t.integer "user_id"
t.integer "room_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "role"
t.integer "last_checked"
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "mail"
t.integer "rooms_user_id"
end
User model:
class User < ApplicationRecord
has_secure_password(validations: false)
has_many :messages
has_many :rooms_users
has_many :rooms, through: :rooms_users
accepts_nested_attributes_for :rooms_users
attr_accessor :register, :mail_confirmation, :login
end
Room model:
class Room < ApplicationRecord
has_many :rooms_users
has_many :users, through: :rooms_users
accepts_nested_attributes_for :rooms_users
has_many :message
end
RoomsUsers model:
class RoomsUsers < ApplicationRecord
belongs_to :user
belongs_to :room
end
And i am trying to get role field from first user's room.
User.first.rooms.first.role
It give's me NoMethodError (undefined method `role' for #). What's wrong?
You're trying to access role field in the rooms table, but it is in rooms_users table. Should be:
User.first.rooms_users.first.role
And remove rooms_user_id from rooms and users table, you don't need it
If you want to access "role" field through Rooms model, you will need to change the place of your "role" field from rooms_users table to rooms table. Doing it you can access "role" using User.first.rooms.first.role.
However if you want to keep "role" field in rooms_users table, so you will need to use User.first.rooms_users.first.role as Vasilisa has already mentioned.
t.integer "rooms_user_id" are not necessary in rooms and users tables. The has_many used in rooms and users are already linking rooms_users with them.
create_table "addresses", force: :cascade do |t|
t.integer "user_id"
t.string "code_postal"
t.string "street_name"
t.string "street_number"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["code_postal"], name: "index_addresses_on_code_postal"
t.index ["user_id"], name: "index_addresses_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "name_first"
t.string "name_last"
t.date "date_birth"
t.string "address_email"
t.integer "address_primary_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
A user can have many addresses, but a user can only have one primary address.
How do I add a foreign key constraint on address_primary_id?
I'm assuming your associations look like this:
class User < ApplicationRecord
belongs_to :address_primary, class_name: Address
has_many :addresses
end
class Address < ApplicationRecord
belongs_to :user
has_one :user_as_primary, class_name: User, foreign_key: :address_primary_id
end
You can create a foreign key you want in a migration with this line:
add_foreign_key :users, :addresses, column: :address_primary_id
Here are the docs on foreign keys in migrations.
This is a rails project using ActiveRecord with Postgres.
Hi I'm working with two CSVs. One is a record of all registered voters in the state. When I created this table I didn't use a generated unique id as an indexed column, but instead used the already assigned state state_voter_id. Schema for Voter table:
create_table "voters", id: false, force: :cascade do |t|
t.string "state_voter_id", null: false
t.string "county_voter_id"
t.string "first_name"
t.string "middle_name"
t.string "last_name"
t.string "suffix"
t.string "birthdate"
t.string "gender"
t.string "add_st_num"
t.string "add_st_name"
t.string "add_st_type"
t.string "add_unit_type"
t.string "add_pre_direction"
t.string "add_post_direction"
t.string "add_unit_num"
t.string "city"
t.string "state"
t.string "zip"
t.string "county"
t.string "precinct"
t.string "leg_dist"
t.string "cong_dist"
t.string "reg_date"
t.string "last_vote"
t.string "status"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["city"], name: "index_voters_on_city"
t.index ["first_name"], name: "index_voters_on_first_name"
t.index ["last_name"], name: "index_voters_on_last_name"
t.index ["state_voter_id"], name: "index_voters_on_state_voter_id", unique: true
t.index ["zip"], name: "index_voters_on_zip"
end
I know want to add in a new table/model of vote records containing the state_voter_id as the reference to the Voter table
This is the migration I tried:
def change
create_table :votes do |t|
t.references :voter, column: :state_voter_id
t.string :county
t.string :date
t.timestamps
end
When I ran the migration It migrated, but when I tried to start seeding voter records I got the following error: ActiveRecord::UnknownPrimaryKey: Unknown primary key for table voters in model Voter. I also noted that the table was set up to take a bigint.
How do I set it up so that I am properly referencing the Voter on state_voter_id, which is an alphanumeric string?
Something along the lines of:
class AddPrimaryKeyToVoters < ActiveRecord::Migration
def change
change_column :voters, :state_voter_id, :primary_key
end
end
In your voters model add
self.primary_key = "state_voter_id"
The problem isn't with your migration, it's with your Model. You need this
class Voter < ApplicationRecord
self.primary_key = 'state_voter_id'
...
end
Note that's assuming Rails 5 with the new ApplicationRecord class. If you're using rails 4 then just inherit from ActiveRecord::Base as usual.
I have a problem, I want to create an hashtags system, but when I run my code, and when I want to create a travel that contain hashtags I have this error :
ActiveRecord::StatementInvalid in TravelsController#create
Could not find table 'tags_travels'
Here is my travel.rb
class Travel < ApplicationRecord
has_many :posts
belongs_to :user
has_and_belongs_to_many :tags
#after / before create
after_create do
travel = Travel.find_by(id: self.id)
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
before_update do
travel = Travel.find_by(id: self.id)
travel.tags.clear
sh = self.hashtags.scan(/#\w+/)
sh.uniq.map do |s|
tag = Tag.find_or_create_by(name: s.downcase.delete('#'))
travel.tags << tag
end
end
end
my tag.rb
class Tag < ApplicationRecord
has_and_belongs_to_many :travels
end
the schema.rb file (just table concerned) :
create_table "tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "topics", force: :cascade do |t|
t.string "title"
t.string "text"
t.string "end_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "post_id"
end
create_table "travels", force: :cascade do |t|
t.string "name"
t.string "trip_type"
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "hashtags"
end
create_table "travels_tags", id: false, force: :cascade do |t|
t.integer "travel_id"
t.integer "tag_id"
t.index ["tag_id"], name: "index_travels_tags_on_tag_id"
t.index
["travel_id"], name: "index_travels_tags_on_travel_id"
end
Someone has a solution ? Thank !
Rails looks for join tables in a specific syntax. Its trying to find tags_travles but uouve created it with travels_tags.
Change your model associations to specify the join table.
has_and_belongs_to_many :travels, :join_table => :travels_tags
And
has_and_belongs_to_many :tags, :join_table => :travels_tags
Heres some info from the docs to help explain the defsult behaviour for join table naming.
"By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order."
http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-join-table
my app has 3 models, defined as follow:
class User < ActiveRecord::Base
has_many :vehicles, dependent: :destroy
has_one :insurance, through: :vehicle
end
class Vehicle < ActiveRecord::Base
belongs_to :user
has_one :insurance, dependent: :destroy
end
class Insurance < ActiveRecord::Base
belongs_to :vehicle
end
The resulting migration does not set any foreign keys for my insurances table. I expected to have two foreign keys, something like user_id and vehicle_id.
The resulting schema.rb file looks like this:
ActiveRecord::Schema.define(version: 20160314141604) do
create_table "insurances", force: :cascade do |t|
t.string "name"
t.date "issue_date"
t.date "expiry_date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
create_table "vehicles", force: :cascade do |t|
t.text "name"
t.date "matriculation_date"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "vehicles", ["user_id"], name: "index_vehicles_on_user_id"
end
Why insurances table has no foreign keys? Thank you
Run the following migrations:
rails g migration AddUserIDToInsurances user:references
rails g migration AddVehicleIDToInsurances vehicle:references
Then run rake db:migrate. This should add the two foreign keys you mentioned to your insurances table.
You have to specifically set the association keys in a migration. If you create a new migration and add:
add_column :vehicles, :user_id, :integer
add_column :insurances, :user_id, :integer
add_index :vehicles, :user_id
add_index :insurances, :user_id
# or whatever columns and indexes you need...
Rails gives you the has_one has_many and belongs_to methods to associate models conveniently with ActiveRecord, but the keys are not auto-generated unless you deliberately configure them in a migration file.