开发者

Rails Select boolean with NULL value

开发者 https://www.devze.com 2023-03-28 12:46 出处:网络
First the environment: Rails 2.1.0, Ruby 1.8.7, Mysql 5.1.54, Ubuntu 11.04 I have a boolean field in my table which starts as NULL, but I can not find a good way to set it to NULL. (This field is ba

First the environment:

Rails 2.1.0, Ruby 1.8.7, Mysql 5.1.54, Ubuntu 11.04

I have a boolean field in my table which starts as NULL, but I can not find a good way to set it to NULL. (This field is basically a yes / no / unanswered field, which true / false / null seems about right for. The client specifically said he would like it to be able to remain null (unanswered).)

Here is my migration (specific names replaced):

class AddQuestionToClients < ActiveRecord::Migration
    def self.up
        add_column :clients, :question, :boolean
    end
    def self.down
        remove_column :clients, :question
    end
end

My controller uses a basic

@client = Client.find(params[:id])
@client.update_attributes(params[:client])

My view has a select (I think this is causing the problem, was never great with form helper selects):

<%= f.select :question, [["Yes", true], ["No", false]], { :include_blank => true, :selected => @client.question } %>

When selecting yes, true is passed; no, false is passed; blank, "" is passed. But "" seems to automatically convert to false when updating the开发者_如何学编程 database.

To get around this, I'm doing this:

params[:client][:question] = (params[:client][:question] == "")? nil : params[:client][:question]

But this can't be the right way to do it. What am I missing?


I just ran into the same problem, and I solved it by making the attribute convert blank to null. In your case, I would add a method to your model class.

class Client < ActiveRecord::Base
  def question=(value)
    value = nil if value == ''
    super(value)
  end
end

This works for both create and update. (I'm using Rails 2.0.5.)


I think that you can do that only in that way server side, because when a data is posted is always not nil. So your solution is correct.

If you want to avoid that ugly code you can do a little trick client side using javascript. In fact if you use a disabled element instead of a blank value that value won't be posted and you get nil on server side.

To do that you can add a submit callback that checks whether the question field is blank and if so disable it before posting data. In that way it will work without any server side code.

To disable an element using jQuery you can see this link. So assuming your form has the #form id you can use this code

$(function() {
  $('#form').submit(function () {
    if ($('question-selector').val() == "") {
      $('question-selector').attr('disabled', true);
    }
  })
});


I had the same problem, i needed null value by default for boolean to represent "not answered"

With Rails 3.2, when i pass "" for a boolean value (blank option) is sets the column to NULL in db.

So problem solved with newer version of rails :)


<%= f.select :question, options_for_select([["Yes", true], ["No", false]], :question) %>


@vdaubry I would only add that it is not really solved ..it is masked because you are using 'select' in your UI. If you are foolish enough to use checkboxes, like me (after all, they are booleans, right?) then your nice default nil value in the db, which we mean to represent 'unknown' is converted to 'false' when rendered in the view, and converted to false in the db, even when it is not updated in the view, same as was described above. In other words, it's a bit brittle to continue to rely on a 3rd value for 'boolean' being consistent.

Furthermore, if ever reporting on this attribute, your reporting code cannot easily deduce the values in the db, if "unknown" is a valid meaning and is obscured.

So I chose to refactor all my booleans making them strings ('yes', 'no', 'unknown') and use radio buttons in the views. Note this only matters for things like data collection UIs, where a user has not got round to finding out the truth, so statistically it matters a lot if it's "unknown".


This isn't mentioned in previous posts, but in Rails 5 this should work if you want to name the nil option

<%= f.select :question, [["Yes", true], ["No", false]], { :include_blank => 'Name this whatever you want, it will be nil when submitted', :selected => @client.question } %>

Tested this on my own project

0

精彩评论

暂无评论...
验证码 换一张
取 消