Rails One-To-One Relationship

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



Leave a reply



Submit