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:
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
How to Open Files Relative to Home Directory
Testing Actionmailer Multipart Emails(Text and HTML Version) with Rspec
How to Delete Specific Characters from a String in Ruby
Best Way to Cache a Response in Sinatra
Converting an Array of Keys and an Array of Values into a Hash in Ruby
Check Ruby Http Response for Success
How to Test a Ruby Application Which Uses Mechanize
Group_By in Rails by 2 or More Attributes
Rubymine - No Ruby Interpreter Configured for the Project
"Ago" Date/Time Functions in Ruby/Rails
Ubuntu 12 - How to Install Ruby and Rails Correctly
Ruby on Rails, Two Models in One Form
Ruby: How to Make a Public Static Method
Augmenting a Model from an External Gem