Rails: Ensure Only One Boolean Field Is Set to True at a Time

Rails: Ensure only one boolean field is set to true at a time

This code is stolen from previous answer and slightly simplified:

def falsify_all_others
Item.where('id != ?', self.id).update_all("default = 'false'")
end

You can use this method in before_save callback in your model.

Actually, it is better to "falsify" only records which values are 'true', like this:

Item.where('id != ? and default', self.id).update_all("default = 'false'")

UPDATE: to keep code DRY, use self.class instead of Item:

self.class.where('id != ? and default', self.id).update_all("default = 'false'")

Rails: Allow only one record of a rails model to have a boolean property true?

ActiveRecord has some update attributes methods that don't trigger callbacks like post.update_column, Post.update_all, etc. So you can use these in a callback like

before_save :set_primary

private
def set_primary
Post.where.not(id: id).update_all(primary: false)
end

When do boolean fields transform to true/false in Rails?

When you set a value in your model the setter will typecast the value:

class Thing
include ActiveModel::Model
include ActiveModel::Attributes
attribute :awesome, :boolean
end

t = Thing.new
t.awesome = "1"
t.awesome # true

If you want to tap into the process the most straight forward way is by redefining the setter.

class Thing
include ActiveModel::Model
include ActiveModel::Attributes
attribute :awesome, :boolean

def awesome=(value)
# do something
super
end
end

When you initialize, create or update a model from a Hash of attributes ActiveModel::AttributeAssignment handles setting the attributes from a hash by looping through the keys and values and calling the appropriate setter.

ActiveModel::Attributes is a previously private API that was exposed in Rails 5 and it forms the cornerstone of ActiveRecord::Attributes which is a more specialized implementation where the model is backed by a database table. In ActiveRecord::Attributes the typecasting is also done in the setter but it also includes stuff like dirty tracking and keeps track of attributes even before they are typecast. ActiveRecord::Attributes not only handles typecasting user input but it also handles typecasting values to and from the database.

ActiveRecord also includes a whole multitude of methods for assigning and updating methods that vary in if they fire callbacks or validations.

"Is this comparable to any callback (e.g. before_validation)? In our case especially, can we make sure it runs before validations are run?

This really depends on which method we are talking about. But in most cases the actual assignment happens before any callbacks are run.

See:

  • https://guides.rubyonrails.org/active_model_basics.html
  • https://api.rubyonrails.org/classes/ActiveModel/Attributes.html
  • https://api.rubyonrails.org/classes/ActiveRecord/Attributes.html

To validate or not to validate boolean field

Whether or not you should validate a boolean attribute for inclusion in [ true, false ] depends entirely on your use case.

You've correctly identified that, in the absence of validation of other code, a boolean field in Rails will always be (after type coercion) true, false, or nil. Rails won't coerce nil to false. If you set a model's boolean attribute to nil and save it, the attribute will be nil, not false, when you fetch the it from the database later.

You can think of nil as a "third state" for a boolean field. Consider a simple survey app that lets users save an unfinished survey to complete later. Suppose a user saves an incomplete survey with the question "Do you eat meat?" unanswered. You don't want to store false in the database because that would indicate that the user answered "no." When the user comes back to finish the survey you want that question to still be unanswered, so you want to store nil in the database.

In cases like the above, it's appropriate (and necessary) not to validate for inclusion in [ true, false ].

However, as a rule of thumb I would say that in all other cases—i.e. in any case where you don't have a specific need for nil values—you should validate boolean fields for inclusion in [ true, false ].

Of course, if you do allow nil you'll need to be careful because, as you know, nil is a falsey value in Ruby. You'll have to explicitly check for "nilness" in places where you might otherwise rely on a value's truthiness or falsiness. That is, instead of this:

if !is_meat_eater
unanswered_questions << :is_meat_eater
end

...which will not behave as intended if is_meat_eater is false, you'll need to explicitly check for nil:

if is_meat_eater.nil?
unanswered_questions << :is_meat_eater
end

Rails one-to-many: Validate field value

Add an unique partial index on a boolean read field and integer student_id field where read is equal true

add_column :books, :read, :boolean, null: false, default: false
add_index :books, [:student_id, :read], unique: true, where: "read=true"

In Book model add unique validation that will works only when book.read == true

validates :read, uniqueness: { scope: :student_id }, if: -> (book) { book.read }

Counting boolean values under rails

May be

@entries.select {|r| r.bool_field1}.size 

I am trying create a button in which boolean function should be performed. below is my view code. Can anyone help me

Basically button_to tag in rails converts in to form itself into html.
so you can use this: -

note: - provide correct path and data that should be send with this button at controller

<% if case.active? %>    
<%= button_to case_path(value: false), data: {confirm: 'Are you sure?'}, method: :patch, class: 'btn btn-default btn-danger' do %>
Unblock
<% end %>
<%else%>
<%= button_to case_path(value: true), data: {confirm: 'Are you sure?'}, method: :patch, class: 'btn btn-default btn-danger' do %>
block
<% end %>
<%end%>

and at controller: -

def your_action
case = Case.find(params[:id])
case.update(active: params[:value])
end

Rails how to use a select list for a boolean field?

In Rails, false is considered blank. You can try on your rails console:

Sample Image

You should remove the presence validation, and set the field to default to false. Or, since it's a boolean, consider true as true, and false or nil as false.



Related Topics



Leave a reply



Submit