Rails one-to-one relationship
why don't you just test before the user tries to add a car?
if worker.car
raise "sorry buddy, no car for you"
else
car = Car.create(user_id: worker.id)
end
Rails: How to call one-to-one relationship in rails
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">
Creating link table to connect one to one relationship of same model
What you want here is really just a normal many to many table setup:
class Book < ApplicationRecord
has_many :book_pages
has_many :pages, through: :book_pages
end
class Page < ApplicationRecord
has_many :book_pages
has_many :books, through: :book_pages
end
class BookPage < ApplicationRecord
belongs_to :book
belongs_to :page
validates_uniqueness_of :book_id, scope: :page_id
end
Uniqueness in this case can be guarenteed by adding a unique index:
add_index :book_pages, [:book_id, :page_id]
Why?
M2M join table setups where you have two foreign keys that are assigned arbitrarily are not a very good design and don't work well with ActiveRecord since you can't define assocations with an OR
clause.
Each association can only have a single foreign key. This means that you can't treat it as a homogenius collection and cannot eager load it.
That means you need to write crappy joins like this instead of being able to work with a proper assocation:
Book.joins(
"LEFT JOIN pages_assocations pa ON pa.left_page_id = books.id OR pa.left_page_id = books.id"
)
And you also have to write steaming piles when creating indirect assocations.
While the table setup with a single row per book/page combo may seem to require more rows on the onset its also much more flexible as you can map out the assocations between books by subqueries, lateral joins or grouping and counting the number of matches.
class Book < ApplicationRecord
has_many :book_pages
has_many :pages, through: :book_pages
def books_with_pages_in_common
Book.where(
id: BookPage.select(:book_id)
.where(page_id: pages)
)
end
end
Weirdness with one to one relationship in Rails
I would suggest you need to use a left outer join here. In Rails 5, this could be written as:
users = team.users.left_outer_join(:assessment)
.where(assessments: { id: nil })
.uniq
Source: https://blog.bigbinary.com/2016/03/24/support-for-left-outer-joins-in-rails-5.html
Rails assignment on a one-to-one relationship
When declaring a has_one
association on an ActiveRecord model it gains the following methods:
association(force_reload = false)
association=(associate)
build_association(attributes = {})
create_association(attributes = {})
create_association!(attributes = {})
Which does not include the shovel operator <<
thus your error that <<
is undefined in this case. It's not a configuration problem. Looks like your config is working fine. Here's the Rails guide with the specific details
http://guides.rubyonrails.org/association_basics.html#has-one-association-reference
The <<
shovel operator is defined along with all these other methods when you include a has_many
or has_and_belongs_to_many
on a model:
collection(force_reload = false)
collection<<(object, ...)
collection.delete(object, ...)
collection.destroy(object, ...)
collection=(objects)
collection_singular_ids
collection_singular_ids=(ids)
collection.clear
collection.empty?
collection.size
collection.find(...)
collection.where(...)
collection.exists?(...)
collection.build(attributes = {}, ...)
collection.create(attributes = {})
collection.create!(attributes = {})
Here's the details:
http://guides.rubyonrails.org/association_basics.html#has-many-association-reference
http://guides.rubyonrails.org/association_basics.html#has-and-belongs-to-many-association-reference
Rails: two models with one-to-one relationship, one controller
Check Nested Model Form Part 1/2 by rails cast. Checkout the rails cast and you can surely figure out :) Its explained for many to many relationships, minor tweeks and you can do it for one to one.
Some sample code you may want to see:
class Wiki < ActiveRecord::Base
has_many :revisions
has_one :latest_revision, :class_name => "Revision", :order => 'updated_at desc', :limit => 1
accepts_nested_attributes_for :revisions
end
class Revision < ActiveRecord::Base
belongs_to :wiki
end
# new Wiki page, first revision
def new
@wiki = Wiki.new
@revision = @wiki.revisions.build
end
def create
@wiki=Wiki.new(params[:wiki])
@wiki.save
end
# adding a Revision to a Wiki page
def edit
@wiki = Wiki.find(params[:id])
@revision = @wiki.revisions.build # creating a new revision on edit
end
def update
@wiki=Wiki.new(params[:wiki])
@wiki.save
end
def show
@wiki = Wiki.find(params[:id])
@revision = @wiki.latest_revision
end
Rails one-to-one works for belongs_to but not for has_one
This is the convention:
Scenario has_one RentalDetail
=> scenario_1.rental_detail.id (has_one docs). It uses the singular form of RentalDetail.
class Scenario < ActiveRecord::Base
has_one :rental_detail
end
Scenario has_many RentalDetail
=> scenario_1.rental_details.pluck(:id) (has_many docs). It uses the pluralized version of RentalDetail.
class Scenario < ActiveRecord::Base
has_many :rental_details
end
As I said, this is the convetion but nobody stops you from naming the associations as you like. You just need to tell the ActiveRecord to use correct class_name
, primary_key
, foreign_key
, etc. Check the docs.
trying to create a one to one relationship
Usually you will want to call
user.profile.country
But if you want to use user.country
you will have to delegate those methods from Profile
to User
like this:
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable
acts_as_voter
enum role: [:user, :admin]
has_many :entries, dependent: :destroy
has_many :reports, dependent: :destroy
has_many :messages
has_one :profile
#delegate method call to profile, check the delegate document for more options.
delegate :country, to: :profile
end
How can I route/reference one to one relationship in Ruby on Rails
You don't need to reference the one-to-one relationship to get a userdetail_path
helper. In your routes.rb
, make sure you have this:
resource :userdetail, only: :show
Related Topics
How to Get the Ruby Documentation from the Command Line
How to Test a Ruby Application Which Uses Mechanize
Rails Scope Find with Current User
What Are the Uppercase and Lowercase Rules of Ruby Method Name
Rails Plugin for API Key + Secret Key Signing
How to Pass Arguments from the Parent Task to the Child Task in Rake
Configuring Jekyll for Github Project Pages
Ruby: What Does the Snippet: (Num & 1) == 0 Exactly Do
How to Switch to Older Versions of the Ruby/Rails Environment
How to Controller (Start/Kill) a Background Process (Server App) in Ruby
How to Monitor Uptime of 20 Websites (Ping or Http) in Node.Js/Ror
Errno::Enoent: No Such File or Directory Ruby
Carrierwave: Create the Same, Unique Filename for All Versioned Files
Differencebetween a Process' Pid, Ppid, Uid, Euid, Gid and Egid