Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails belongs_to optional but check exists if passed

I have an attribute that I'd like to be optional in a belongs_to since a user doesn't have to belong to a team right away.

class User < ActiveRecord::Base
  belongs_to :team, optional: true
end

User created without team_id being passed in:

irb(main):001:0> User.create()
D, [2019-08-16T18:56:53.961520 #1] DEBUG -- :    (0.4ms)  BEGIN
D, [2019-08-16T18:56:53.988354 #1] DEBUG -- :   SQL (0.7ms)  INSERT INTO "users" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id"  [["created_at", "2019-08-16 18:56:53.985875"], ["updated_at", "2019-08-16 18:56:53.985875"]]
D, [2019-08-16T18:56:54.017858 #1] DEBUG -- :    (1.0ms)  COMMIT
=> #<User id: 5, provider: nil, uid: nil, name: nil, email: nil, oauth_token: nil, oauth_expires_at: nil, created_at: "2019-08-16 18:56:53", updated_at: "2019-08-16 18:56:53", team_id: nil, pagerduty_id: nil, slack_user_id: nil, admin: false>

This is fine but when I do pass in a team_id for this user rails doesn't check to see if that record exists in the teams table before creating the user record. This can cause team_id to get passed for a team that doesn't exist in the teams database.

Teams in our db currently:

D, [2019-08-16T18:57:10.745090 #1] DEBUG -- :   Team Load (0.8ms)  SELECT "teams".* FROM "teams"
=> #<ActiveRecord::Relation [#<Team id: 1, pagerduty_service_key: nil, pagerduty_id: nil, name: "something", slack_channel: nil, slack_usergroup: nil>]>

Creating a user with team_id of 2 still works:

User.create(team_id: 2)
D, [2019-08-16T18:59:12.776053 #1] DEBUG -- :    (1.7ms)  BEGIN
D, [2019-08-16T18:59:12.783799 #1] DEBUG -- :   SQL (1.3ms)  INSERT INTO "users" ("team_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["team_id", 2], ["created_at", "2019-08-16 18:59:12.777772"], ["updated_at", "2019-08-16 18:59:12.777772"]]
D, [2019-08-16T18:59:12.789468 #1] DEBUG -- :    (1.9ms)  COMMIT
=> #<User id: 6, provider: nil, uid: nil, name: nil, email: nil, oauth_token: nil, oauth_expires_at: nil, created_at: "2019-08-16 18:59:12", updated_at: "2019-08-16 18:59:12", team_id: 2, pagerduty_id: nil, slack_user_id: nil, admin: false>

Removing the optional: true from the model validates the record exists but it also makes it so a NULL value isn't allowed anymore. Is there a rails way to check team_id exists in the teams table without adding a foreign key at the database level?

like image 568
PurrBiscuit Avatar asked Oct 28 '25 05:10

PurrBiscuit


1 Answers

Unfortunately, with optional option it turns off presence validation for your record, but you can add custom validation in your model:

class User < ActiveRecord::Base
  belongs_to :team, optional: true

  validates_presence_of :team, if: :team_id_present?

private

  def team_id_present?
    team_id.present?
  end
end
like image 119
edariedl Avatar answered Oct 29 '25 19:10

edariedl



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!