In the example below saving a model results in duplicate insertions.
shipment_params = {name: "Guy", from_country: "US", from_city: "a Ferry", from_state: "NY", from_postal_code: "11232-1716", from_street_address: "Broadway, 1", to_country: "US", to_city: "idge", to_state: "MA", to_postal_code: "01234-5678", to_street_address: "Massachusetts Avenue, 1234", service_code: "GROUND"}
shipment = Shipment.new(shipment_params)
shipment.save!
class Shipment < ActiveRecord::Base
has_many :shippings
has_many :orders, :through => :shippings
end
class Shipping < ActiveRecord::Base
belongs_to :order
belongs_to :shipment
end
class Order < ActiveRecord::Base
has_many :shippings
has_many :transactions #, :class_name => "OrderTransaction"
has_many :shipments, :through => :shippings
end
The following SQL is shown:
irb(main):014:0> #shipment.save
(0.3ms) BEGIN
SQL (0.4ms) INSERT INTO `shipments` (`name`, `from_country`, `from_city`, `from_state`, `from_postal_code`, `from_street_address`, `to_country`, `to_city`, `to_state`, `to_postal_code`, `to_street_address`, `service_code`, `created_at`, `updated_at`) VALUES ('121', 'US', 'ds Ferry', 'NY', '33-1716', 'd, 329', 'US', 'ss', 'ss', '1234-1228', 'r Avenue, 343', 'GROUND', '2016-03-14 15:04:15', '2016-03-14 15:04:15')
SQL (5.0ms) INSERT INTO `orders` (`created_at`, `updated_at`) VALUES ('2016-03-14 15:04:15', '2016-03-14 15:04:15')
SQL (0.3ms) INSERT INTO `shippings` (`shipment_id`, `order_id`, `created_at`, `updated_at`) VALUES (3, 6, '2016-03-14 15:04:15', '2016-03-14 15:04:15')
SQL (0.3ms) INSERT INTO `shippings` (`shipment_id`, `order_id`, `created_at`, `updated_at`) VALUES (3, 6, '2016-03-14 15:04:15', '2016-03-14 15:04:15')
(4.1ms) COMMIT
=> true
What do you think?
Related
Hi I'm trying to create an app that has items users are selling. I have a table for Users selling the item and a table for items, but I'm a little confused about how I should setup the next table for the buyer. I have a separate table that is many to many between User and Item tracking user_id and item_id. Should I be creating a similar table tracking buyer_id and item_id? I want to be able to track what item has been bought from which user and vs versa. User and Buyers are from the same User table.
Thanks!
Edit:
class UsersController < ApplicationController
def my_page
#user = current_user
#seller_items = current_user.seller_orders.map { |so| so.order_items.map { |oi| { item: oi.item } } }.flatten
#seller_items.to_a
end
end
A more complete answer, with less models, and named joins. You might want to "merge" the order and order_items tables, and remove the multiple if you're dealing with singular items for sale, e.g. cars, but for anything that is either bought in bulk or might be sold at the same time as something else you might want this layout:
generate your models:
rails g model User name:string
rails g model Item name:string
rails g model Order order_date:time status:string
rails g model OrderItem order:references item:references multiple:integer
modify create_order to add in the additional references:
def change
create_table :orders do |t|
t.time :order_date, index: true, null: false
t.string :status
t.references :buyer, index: true, null: false, foreign_key: {to_table: :users}
t.references :seller, index: true, null: false, foreign_key: {to_table: :users}
t.timestamps
end
migrate the models:
rake db:migrate
== 20201126090851 CreateUsers: migrating ======================================
-- create_table(:users)
-> 0.0036s
== 20201126090851 CreateUsers: migrated (0.0039s) =============================
== 20201126090858 CreateItems: migrating ======================================
-- create_table(:items)
-> 0.0030s
== 20201126090858 CreateItems: migrated (0.0032s) =============================
== 20201126091129 CreateOrders: migrating =====================================
-- create_table(:orders)
-> 0.0077s
== 20201126091129 CreateOrders: migrated (0.0081s) ============================
== 20201126091209 CreateOrderItems: migrating =================================
-- create_table(:order_items)
-> 0.0065s
== 20201126091209 CreateOrderItems: migrated (0.0067s) ========================
modify the models to add the joins:
app/models/user.rb
::::::::::::::
class User < ApplicationRecord
has_many :buyer_orders, class_name: "Order", foreign_key: :buyer, inverse_of: :buyer
has_many :seller_orders, class_name: "Order", foreign_key: :seller, inverse_of: :seller
end
::::::::::::::
app/models/item.rb
::::::::::::::
class Item < ApplicationRecord
has_many :order_items, inverse_of: :item
end
::::::::::::::
app/models/order.rb
::::::::::::::
class Order < ApplicationRecord
has_many :order_items, inverse_of: :order
belongs_to :seller, class_name: "User", inverse_of: :seller_orders
belongs_to :buyer, class_name: "User", inverse_of: :buyer_orders
end
::::::::::::::
app/models/order_item.rb
::::::::::::::
class OrderItem < ApplicationRecord
belongs_to :order, inverse_of: :order_items
belongs_to :item, inverse_of: :order_items
end
insert data:
User.create(name: "hello")
User.create(name: "again")
Item.create(name: "whatever")
Order.create(buyer: User.first, seller: User.last, order_date: Time.now())
OrderItem.create(item: Item.first, order: Order.first, multiple: 1)
test the output:
Check the status of the order:
2.7.0 :002 > Order.first
(0.5ms) SELECT sqlite_version(*)
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Order id: 1, order_date: "2000-01-01 09:26:22", status: nil, buyer_id: 1, seller_id: 2, created_at: "2020-11-26 09:26:22", updated_at: "2020-11-26 09:26:22">
2.7.0 :003 > Order.first.seller
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ? [["LIMIT", 1]]
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]]
=> #<User id: 2, name: "again", created_at: "2020-11-26 09:25:26", updated_at: "2020-11-26 09:25:26">
2.7.0 :004 > Order.first.buyer
Order Load (0.2ms) SELECT "orders".* FROM "orders" ORDER BY "orders"."id" ASC LIMIT ? [["LIMIT", 1]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]]
=> #<User id: 1, name: "hello", created_at: "2020-11-26 09:25:18", updated_at: "2020-11-26 09:25:18">
Check the "buyer orders" of the first user:
2.7.0 :013 > User.first.buyer_orders
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."buyer_id" = ? LIMIT ? [["buyer_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Order id: 1, order_date: "2000-01-01 09:26:22", status: nil, buyer_id: 1, seller_id: 2, created_at: "2020-11-26 09:26:22", updated_at: "2020-11-26 09:26:22">]>
check the "seller orders" of the second user:
2.7.0 :014 > User.last.seller_orders
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT ? [["LIMIT", 1]]
Order Load (0.3ms) SELECT "orders".* FROM "orders" WHERE "orders"."seller_id" = ? LIMIT ? [["seller_id", 2], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Order id: 1, order_date: "2000-01-01 09:26:22", status: nil, buyer_id: 1, seller_id: 2, created_at: "2020-11-26 09:26:22", updated_at: "2020-11-26 09:26:22">]>
for peace of minds sake, check that the first user doesn't have any seller orders:
2.7.0 :015 > User.first.seller_orders
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
Order Load (0.2ms) SELECT "orders".* FROM "orders" WHERE "orders"."seller_id" = ? LIMIT ? [["seller_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy []>
2.7.0 :016 >
Controller
class UsersController < ApplicationController
def my_page
#user = current_user
#seller_orders = current_user.seller_orders
# remember that you might want to filter this in the future
# from_date = params[:from_date].present? ? params[:from_date] : Time.at(0)
# to_date = params[:to_date].present? ? params[:to_date] : Time.now()
# #seller_orders = #seller_orders.where(order_date: from_date..to_date)
end
end
view (I use haml)
%h1
= #user.username
Seller Orders
- #seller_orders.each do |so|
%table.seller_order{id: "seller_order_#{so.id}"}
%tr
%th Order Date:
%td= so.order_date
%tr
%th Buyer:
%td= so.buyer.username
%tr.spacer
%td{colspan: 2}
%tr
%th Item
%th Multiple
- so.order_items.each do |oi|
%tr
%td= oi.item.name
%td= oi.multiple
seller items
#seller_items = #seller_orders.map{|so| so.order_items.map{|oi| {multiple: oi.multiple, item: oi.item} }.flatten
or possibly (written from memory, not tested)
#seller_items = OrderItem.select("sum(order_items.multiple) as multiple, order_items.item_id as item_id").joins(:orders).joins(:buyer).where("users.id = ?", User.first.id).group("item_id")
You need something in the middle indeed - that's typicall called an "Order" in e-commerce with:
Link to User
Link to Item
but also maybe some more attributes:
Date of the sale
Status (cart/order/paid/delivered)
So indeed - you'll want an additional model there
class Seller < ApplicationRecord
belongs_to :user
has_many selling_items
has_many :items, through: :selling_items
end
class Buyer < ApplicationRecord
belongs_to :user
has_many bought_items
has_many :items, through: :bought_items
end
class Items < ApplicationRecord
end
class BoughtItem < ApplicationRecord
belongs_to :buyer
belongs_to :item
end
class SellingItem < ApplicationRecord
belongs_to :seller
belongs_to :item
end
class User < ApplicationRecord
end
Bullet gem detected an eager loading on create. Consider the following models:
class User < ActiveRecord::Base
has_many :user_banks
has_many :banks, through: :user_banks
end
class Bank < ActiveRecord::Base
belongs_to :country
belongs_to :currency
has_many :user_posts
has_many :users, through: :user_banks
end
class UserBank < ActiveRecord::Base
belongs_to :user
belongs_to :bank
end
In my controller, when creating user:
# GET /user/new
def new
#user = User.new
end
# POST /users
def create
#user = User.new(user_params)
if #user.save
redirect_to user_path(#user), notice: I18n.t('views.action.created')
else
render :new
end
end
private
def user_params
params.fetch(:user, {}).permit(:name, :email, bank_ids: [])
end
I've got an error;
Bullet::Notification::UnoptimizedQueryError:
user: ruby
POST /admin/users
USE eager loading detected
Bank => [:country]
Add to your query: .includes([:country])
Call stack
/src/app/controllers/admin/users_controller.rb:36:in `create'
The Rails code that eager loads has_many through associations is unfortunately a bit buggy.
How do I solve this? to eager load the country and currency of the Bank.
If you will try in Rails console something like this;
[1] pry(main)> User.new(name: 'test', email: 'test#test.com', bank_ids: [1, 2]).save!
Country Load (1.3ms) SELECT `countries`.`id`, `countries`.`created_at`, `countries`.`updated_at`, `countries`.`code` FROM `countries` WHERE `countries`.`id` = 1 LIMIT 1
Currency Load (0.4ms) SELECT `currencies`.* FROM `currencies` WHERE `currencies`.`id` = 1 LIMIT 1
Country Load (1.3ms) SELECT `countries`.`id`, `countries`.`created_at`, `countries`.`updated_at`, `countries`.`code` FROM `countries` WHERE `countries`.`id` = 1 LIMIT 1
Currency Load (0.4ms) SELECT `currencies`.* FROM `currencies` WHERE `currencies`.`id` = 1 LIMIT 1
User Create (0.5ms) INSERT INTO `users` (`name`, `email`, `created_at`, `updated_at`) VALUES ('test', 'test#test.com', '2020-06-25 06:18:50', '2020-06-25 06:18:50')
UserBank Create (1.0ms) INSERT INTO `user_banks` (`user_id`, `bank_id`, `created_at`, `updated_at`) VALUES (1, 1, '2020-06-25 06:18:50', '2020-06-25 06:18:50')
UserBank Create (0.4ms) INSERT INTO `user_banks` (`user_id`, `bank_id`, `created_at`, `updated_at`) VALUES (1, 2, '2020-06-25 06:18:50', '2020-06-25 06:18:50')
Try:
User.new(name: 'test',
email: 'test#test.com',
banks: Bank.eager_load(:country, :currency).find([1, 2])
).save!
I have four models in Sport, Gold, Silver, and Bronze with a one to one relationship between sport and the other three. Every instance of sport must have an instance of Gold, Silver and Bronze; and three are to be created using a callback function in the Sports model. These callback function is one throwing up the error that i have been able to trace as the rails error stack produced is just a single line.
My Code
MODELS
Sport
class Sport < ActiveRecord::Base
validates :sportname, presence: true,
uniqueness: { case_sensitive: false }
has_one :gold, inverse_of: :sport, :dependent => :destroy
has_one :silver, inverse_of: :sport, :dependent => :destroy
has_one :bronze, inverse_of: :sport, :dependent => :destroy
accepts_nested_attributes_for :gold
accepts_nested_attributes_for :silver
accepts_nested_attributes_for :bronze
after_validation :build_default_medals, on: :create
def build_default_medals
self.build_gold
self.build_silver
self.build_bronze
end
end
Gold
class Gold < ActiveRecord::Base
belongs_to :sport #, inverse_of: :gold
validates_associated :sport, presence: true
belongs_to :team, inverse_of: :golds, counter_cache: true
validates_associated :team, :if => :create, allow_nil: true
accepts_nested_attributes_for :team
accepts_nested_attributes_for :sport
end
Silver
class Silver < ActiveRecord::Base
belongs_to :sport #, inverse_of: :silver
validates_associated :sport, presence: true
belongs_to :team, inverse_of: :silvers, counter_cache: true
validates_associated :team, :if => :create, allow_nil: true
accepts_nested_attributes_for :team
accepts_nested_attributes_for :sport
end
Bronze
class Bronze < ActiveRecord::Base
belongs_to :sport #, inverse_of: :bronze
validates_associated :sport, presence: true
belongs_to :team, inverse_of: :bronzes, counter_cache: true
validates_associated :team, :if => :create, allow_nil: true
accepts_nested_attributes_for :team
accepts_nested_attributes_for :sport
end
The callback after_validation :build_default_medals, on: :create is where the error is, producing this in my log
Started POST "/admin/sports" for 127.0.0.1 at 2016-07-14 14:52:22 -0400
Processing by Admin::SportsController#create as HTML
Parameters:{"utf8"=>"√",authenticity_token"=>"jss1O4bSJd3hcqxuSpu/KAxaowB7d
g5pLZw55oGDf1M=", "sport"=>{"sportname"=>"boxing"}, "commit"=>"Create Sport"}
User Load (1.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 (0.0ms) BEGIN
Sport Exists (1.0ms) SELECT 1 AS one FROM `sports` WHERE `sports`.`sportname` = 'boxing' LIMIT 1
SQL (1.0ms) INSERT INTO `sports` (`created_at`, `sportname`, `updated_at`) VALUES ('2016-07-14 18:52:22', 'boxing', '2016-07-14 18:52:22')
SQL (15.1ms) UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` = 13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms) INSERT INTO `golds` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22')
SQL (1.0ms) UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` =13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms) INSERT INTO `silvers` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22')
SQL (1.0ms) UPDATE `sports` SET `created_at` = '2016-07-14 18:52:22', `id` =13, `sportname` = 'boxing', `updated_at` = '2016-07-14 18:52:22' WHERE `sports`.`id` = 13
SQL (1.0ms) INSERT INTO `bronzes` (`created_at`, `sport_id`, `updated_at`) VALUES ('2016-07-14 18:52:22', 13, '2016-07-14 18:52:22') (72.2ms)
ROLLBACK
Completed 500 Internal Server Error in 213ms
SystemStackError (stack level too deep): actionpack (4.1.8) lib/action_dispatch/middleware/reloader.rb:79
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_source.erb (2.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (4.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (7.0ms)
Rendered C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/actionpack-4.1.8/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (145.1ms)
I am curious as to why the callback triggers update after inserting and what exactly is triggering the ROLLBACK and infinite loop for Stack Level Too Deep. Any insight is appreciated. Thanks.
EDIT
Using after_create :build_default_medals in place of after_validation :build_default_medals, on: :creation produces
Started POST "/admin/sports" for 127.0.0.1 at 2016-07-14 16:19:24 -0400
Processing by Admin::SportsController#create as HTML
Parameters: {"utf8"=>"√","authenticity_token"=>"3LrwB6+nD9PJ9EwxEgIGhN3rVHP3UPLOHUz9MXWRJ4Y=", "sport"=>{"sportname"=>"dancing"}, "commit"=>"Create Sport"}
User Load (1.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 (0.0ms) BEGIN
Sport Exists (1.0ms) SELECT 1 AS one FROM `sports` WHERE `sports`.`sportname` = 'dancing' LIMIT 1
SQL (1.0ms) INSERT INTO `sports` (`created_at`, `sportname`,`updated_at`) VALUES ('2016-07-14 20:19:24', 'dancing', '2016-07-14 20:19:24')
Gold Load (2.0ms) SELECT `golds`.* FROM `golds` WHERE `golds`.`sport_id` =8 LIMIT 1
Silver Load (1.0ms) SELECT `silvers`.* FROM `silvers` WHERE `silvers`.`sport_id` = 8 LIMIT 1
Bronze Load (1.0ms) SELECT `bronzes`.* FROM `bronzes` WHERE `bronzes`.`sport_id` = 8 LIMIT 1
(45.5ms) COMMIT
EDIT FOR undefined method 'create' for #<Gold:0x63bf820>
def build_default_medals
#Gold.create(sport: self, team: nil)
#Silver.create(sport: self, team: nil)
#Bronze.create(sport: self, team: nil)
self.create_gold(team: nil)
self.create_silver(team: nil)
self.create_bronze(team: nil)
end
replace
after_validation :build_default_medals, on: :create
with
after_create :build_default_medals
You are trying to build associated models while sport is still a new record and not a persisted one. validates_associated :sport, presence: true causes a circular dependency and will give error.
I reproduced and tested with this change. It will work fine.
For saved object, use self.create_gold instead of self.build_gold, like this
def build_default_medals
self.create_gold
self.create_silver
self.create_bronze
end
Also remove accepts_nested_attributes_for :sport from Gold, Silver and Bronze model. Refer - https://github.com/rails/rails/issues/7809
class Project < ActiveRecord::Base
has_many :accounts
has_many :sites, through: :accounts
end
class Site < ActiveRecord::Base
has_many :accounts
has_many :projects, through: :accounts
accepts_nested_attributes_for :accounts
end
class Account < ActiveRecord::Base
belongs_to :site
belongs_to :project
end
p = Project.find(1)
2.1.4 :011 > p.sites.create({"url"=>"site.ru", "accounts_attributes"=>{"0"=>{"email"=>"mail#site.ru"}}})
(0.3ms) BEGIN
SQL (1.8ms) INSERT INTO `sites` (`created_at`, `updated_at`, `url`) VALUES ('2015-09-04 07:09:53', '2015-09-04 07:09:53', 'site.ru')
SQL (0.3ms) INSERT INTO `accounts` (`created_at`, `email`, `site_id`, `updated_at`) VALUES ('2015-09-04 07:09:53', 'mail#site.ru', 3, '2015-09-04 07:09:53')
SQL (0.3ms) INSERT INTO `accounts` (`created_at`, `project_id`, `site_id`, `updated_at`) VALUES ('2015-09-04 07:09:53', 1, 3, '2015-09-04 07:09:53')
(1.2ms) COMMIT
=> #<Site id: 3, url: "site.ru", created_at: "2015-09-04 07:09:53", updated_at: "2015-09-04 07:09:53">
Question:
Why are added 2 record?
To add a single entry in the Account model with fields site_id, project_id, email?
The first account record is created automatically, because the Site is related to the Project through the Account.
The second record is created because you have accepts_nested_attributes_for :accounts in your Site model, and you pass the nested attributes while creating the Site record.
Could you clarify, what you want to archieve?
I'm new to rails and I want to know how to fetch a one-to-one relationship. I want to fetch users city. In my postgresql database I have:
cities Table:
city:varchar
zipcode: integer
users Table
name:varchar
city_id:int
and in city and user model I have:
class City < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :city
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I tried the following in my search controller but didnt work, when logged in:
current_user.city
I get the following error
Processing by SearchController#index as HTML
Parameters: {"utf8"=>"✓", "q"=>"", "criteria"=>"1", "commit"=>"Search"}
User Load (1.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = 6 ORDER BY "users"."id" ASC LIMIT 1
PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1
Completed 500 Internal Server Error in 11ms
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column cities.user_id does not exist
LINE 1: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" =...
^
: SELECT "cities".* FROM "cities" WHERE "cities"."user_id" = $1 LIMIT 1):
why am I suppose to add a user_id column to cities table, when I have cities foreign key in users table? I dont want to add user_id into cities table.
You can use has_one :through association with join table. Some example for you below.
user model:
class User < ActiveRecord::Base
has_one :city, through: :user_city
has_one :user_city
end
city model:
class City < ActiveRecord::Base
belongs_to :user
end
user city join model:
class UserCity < ActiveRecord::Base
belongs_to :city
belongs_to :user
end
migration for join tables:
class JoinUserCity < ActiveRecord::Migration
def change
create_table :user_cities do |t|
t.integer :user_id
t.integer :city_id
end
end
end
Test in rails console:
=> u = User.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:14.595728"], ["updated_at", "2014-12-07 15:47:14.595728"]]
(3.3ms) commit transaction
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> nil
=> c = City.create
(0.1ms) begin transaction
SQL (0.5ms) INSERT INTO "cities" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2014-12-07 15:47:24.535039"], ["updated_at", "2014-12-07 15:47:24.535039"]]
(3.3ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):004:0> u.city = c
UserCity Load (0.3ms) SELECT "user_cities".* FROM "user_cities" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "user_cities" ("city_id", "user_id") VALUES (?, ?) [["city_id", 1], ["user_id", 4]]
(1.0ms) commit transaction
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
irb(main):005:0> u.save
(0.1ms) begin transaction
(0.1ms) commit transaction
=> true
=> u = User.last
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
=> #<User id: 4, created_at: "2014-12-07 15:47:14", updated_at: "2014-12-07 15:47:14">
=> u.city
City Load (0.2ms) SELECT "cities".* FROM "cities" INNER JOIN "user_cities" ON "cities"."id" = "user_cities"."city_id" WHERE "user_cities"."user_id" = ? LIMIT 1 [["user_id", 4]]
=> #<City id: 1, created_at: "2014-12-07 15:47:24", updated_at: "2014-12-07 15:47:24">
take a look at the document of has_one and belogns_to,
belongs_to(name, options = {})
Specifies a one-to-one association with another class. This method should only be used if this class
contains the foreign key. If the other class contains the foreign key, then you should use has_one
instead.
as the user table has the foreign key, you should change your model definition like this
class City < ActiveRecord::Base
has_one :user
end
class User < ActiveRecord::Base
belongs_to :city
end