How to make a virtual attribute be a boolean field
Asked Answered
P

4

5

I'm trying to get my virtual attribute that is a boolean to work. In this example, lets call the virtual boolean field children:

models/parent.rb

Parent
 attr_accessible :children
 attr_accessor :children
 validates_inclusion_of :children, :in => [true, false]

 def self.children=(boolean)
 end

end

parents/new.html.erb

<%= form_for @parent do |f| %>
  <%= f.check_box :children %>
  <%= f.submit "Create" %>
<% end %>

Right now when I try to use it, (create a parent) it gives me the error

Children is not included in the list

when the validation comes up.

How do I write this?

Polynices answered 7/8, 2012 at 23:22 Comment(0)
A
8

The param you get from the browser is a String (based on your comment to the other answer: «Instead of true and false though its using 0 and 1."parent"=>{"children"=>"1"}»). Your validation checks whether it is a boolean.

I suggest the following solution:

First, Remove your def self.children=() method, it does nothing at all in your current implementation (it is a class method and never called).

Then, implement a custom accessor that converts the String param into a boolean:

class Parent
  attr_reader :children

  def children=(string_value)
    @children = (string_value == '1')
  end

  validates_inclusion_of :children, :in => [true, false]
end

With that your original validation should work just fine.

Alagoas answered 8/8, 2012 at 8:23 Comment(2)
Thank you. Still trying to understand ruby, appreciate it!Polynices
But still ugly. There should be boolean_attr_accessor implemented somewhere. If not, it's amazing :)Engels
G
12

Rails 5 has now added the attribute method for this.

class Parent
  attribute :children, :boolean
end

It's officially called "attributes API" and you can find the documentation here: https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html

Gingili answered 21/12, 2018 at 14:35 Comment(0)
A
8

The param you get from the browser is a String (based on your comment to the other answer: «Instead of true and false though its using 0 and 1."parent"=>{"children"=>"1"}»). Your validation checks whether it is a boolean.

I suggest the following solution:

First, Remove your def self.children=() method, it does nothing at all in your current implementation (it is a class method and never called).

Then, implement a custom accessor that converts the String param into a boolean:

class Parent
  attr_reader :children

  def children=(string_value)
    @children = (string_value == '1')
  end

  validates_inclusion_of :children, :in => [true, false]
end

With that your original validation should work just fine.

Alagoas answered 8/8, 2012 at 8:23 Comment(2)
Thank you. Still trying to understand ruby, appreciate it!Polynices
But still ugly. There should be boolean_attr_accessor implemented somewhere. If not, it's amazing :)Engels
T
1

Is it possible that the params[:children] is a string? and it expected a boolean.

Tirado answered 7/8, 2012 at 23:48 Comment(4)
When I look at the form its actually a hidden input. Hmmmmm..... i.e. <input name="parent[children]" type="hidden" value="0">. Is that what you mean?Polynices
If you check the console and see the params, I think children will be a string not a boolean. So the validation doesn't match true != "true"Tirado
I see now. Instead of true and false though its using 0 and 1."parent"=>{"children"=>"1"}. Now I put this validation instead: validates_inclusion_of :children, :in => [1, 0] but why doesn't it work? Or even better, can I change it to use true and false?Polynices
One solution should be to use a custom validation => guides.rubyonrails.org/…Tirado
H
1

There is no need to manually define a children 'setter' method, because that's exactly what attr_accessor does automatically. Try removing your def self.children=(boolean) method.

Haire answered 8/8, 2012 at 0:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.