Skip to content

Ruby on Rails + Formtastic: Not checking checkboxes for multiple checked answers #917

Closed
ltrevisanDU opened this Issue Feb 5, 2013 · 10 comments

2 participants

@ltrevisanDU

I apologize if this is a repeat issue, but the searches I ran either didn't have enough information for a solution or wasn't quite the same issue I was having. So, I'm posting here.

I've put my issue up on Stack Overflow as well, but thought going directly to the source might be a good start as well.

http://stackoverflow.com/questions/14696376/ruby-on-rails-formtastic-not-checking-checkboxes-for-multiple-checked-answers

If you need more information or me to list it out here, please let me know.

Thanks in advance for any help you can give me.

@ltrevisanDU

I finally solved this issue. It had nothing to do with how the data was getting saved and everything to do with how I was passing the data to Formtastic.

First, I had to create join table between the question response table and the survey option table. Then I had to format how the data was accessing ALL of the survey options (based on the question) and ALL of the checked options for the question response:

class QuestionResponse
    has_many :question_response_options
    has_many :survey_options, :through => :question_response_options

    # Takes all the survey options that are stored in the join
    # table and puts the id's into an array
    def question_response_options
        opts = []
            self.survey_options.each do |option|
        opts << option.id.to_s
        end
        opts
    end
end


class QuestionResponseOption
    belongs_to :question_response
    belongs_to :survey_option
end


class SurveyQuestion < ActiveRecord::Base
    # Creates hash of option name to id
    # { "Law and Order" => 13 }
    def options
        opts = {}
        survey_options.each do |option|
            opts[option.option] = option.id.to_s
        end
        opts
    end
end

Then in Formtastic, I had to change up how I sent information across:

= ff.input :question_response_options, :as => :check_boxes, :collection => ff.object.survey_question.options, :for => :question_response_options

The input had to be for the join table, the collection needed to be all of the options for the given question, and the :for let me join the two by ID.

Only thing I had to do after that is save the checked options myself, which I did in the controller.

@ltrevisanDU ltrevisanDU closed this Feb 6, 2013
@twalpole
Collaborator
twalpole commented Feb 6, 2013

@ltrevisan - I dont fully understand exactly what you're doing with this code since large parts appear to be missing, but I just wanted to point out that the has_many relationships provide you with methods such as QuestionResponse#survey_option_ids through which you can get and set the ids of the associated records. So rather than overriding the question_response_options accessor you might want to look at some of the other facilities provide by has_many

@ltrevisanDU

@twalpole I tried the has_many approach the first time and subsequent times, which in turn ONLY gave me the options IFF their was a question response options record stored. The rest of the options were never called.

Another search and multiple failed attempts later, I came across a post by justinfrench that in order for the model magic to work / check the checkboxes was to make sure they were passing the same data in the same format - in this case an integer. The best way to do this was to either overwrite the accessor OR create a separate one. Since I had no use for the accessor past this, why not just overwrite it?

And yes, the above code has large parts missing. I didn't think posting every association was necessary. Granted, I may have missed a few that would have been helpful.

@twalpole
Collaborator
twalpole commented Feb 6, 2013

@ltrevisan I would say that changing the question_response_options accessor from returning QuestionResponseOption objects to instead return an array of SurveyOption ids may be confusing in the future for maintenance or to any other developer that has to come along and work on the code.

@ltrevisanDU

@twalpole Do you have another idea? This was my last attempt after spending the past 3 days on the internet trying to find a solution before scrapping formtastic and doing a complete rewrite with another form helper.

Technically, survey option id's are stored in the join table anyway. To make it more "understandable" I can take out the lookup table to SurveyOption and use the foreign key in the model. I only did the lookup (and still do) because I at first assumed I needed the option name as well as the ID.

@twalpole
Collaborator
twalpole commented Feb 6, 2013

ltrevisan - ok I just threw a little test together and from what you've said above I think you have the following classes

class QuestionResponseOption < ActiveRecord::Base
  belongs_to :question_response
  belongs_to :survey_option
end

class QuestionResponse < ActiveRecord::Base
  has_many :question_response_options
  has_many :survey_options, :through => :question_response_options
  belongs_to :survey_question

  attr_accessible :survey_option_ids
end

class SurveyOption < ActiveRecord::Base
  belongs_to :survey_question
end

class SurveyQuestion < ActiveRecord::Base
  has_many :survey_options
end

in which case the following works fine for me -- showing all options and allowing selection and deselection of any of the answers

f.input :survey_options, :as => :check_boxes, collection: f.object.survey_question.survey_options

This assumes the SurveyOption has a name attribute that is the actual text you want shown since the collection option will automatically create [:name, :id] from objects passed to it -- if its not name then you'll need to adjust that set of objects passed appropriately

@ltrevisanDU

I appreciate the answer, but that looks nearly identical to what I had prior to the fix I posted above. I believe when I had a similar set up, I was getting the options to display (visually) properly but nothing would stay checked after save. E.G. You could select/deselect the options, save the form, etc, just fine, but if you submitted the form, the options would not populate with the answers you had previously selected.

Have you verified submission and those options are getting checked? If so, I'll look into changing it back and post my success or failure. I'm just not so sure it won't do the same thing again.

By the way, my classes are identical with the exception of SurveyQuestion (has another join table) and the attr_accessible (currently).

@twalpole
Collaborator
twalpole commented Feb 6, 2013

@lltrevisan - yep confirmed it worked fine - I have pushed my simple test up to github at https://github.com/twalpole/demo_for_ltrevisan.git
I manually created the following objects so there was something to try with, went to /question_responses, edited the QuestionResponse I had created, checked options, submitted, re-edited verified they were set, unset them, submitted, and verified they were unset

SurveyQuestion id: 1, created_at: "2013-02-06 20:02:27", updated_at: "2013-02-06 20:02:27"
SurveyOption id: 1, survey_question_id: 1, created_at: "2013-02-06 20:03:07", updated_at: "2013-02-06 20:10:41", name: "first"
SurveyOption id: 2, survey_question_id: 1, created_at: "2013-02-06 20:06:37", updated_at: "2013-02-06 20:06:37", name: "second"
QuestionResponse id: 1, survey_question_id: 1, created_at: "2013-02-06 20:09:16", updated_at: "2013-02-06 20:09:16"

@ltrevisanDU

I never hit QuestionResponse. QuestionResponse gets accessed from Response table - which was never posted.

My form is:

= semantic_form_for @response do |f|
    = f.inputs do
         = f.semantic_fields_for :question_responses do |ff|
             = ff.input :question_response_options, :as => :check_boxes, :collection => ff.object.survey_question.options, :for => :question_response_options

I've pulled down your demo and I'll take a look. Thanks.

@ltrevisanDU

I applied the same associations and updated the code and views. I see the check boxes, but nothing gets checked after submission. My guess is that I still have associations incorrect due to how Response and QuestionResponse interact and/or I'm accessing the QuestionResponse through Response.

There is probably a better way to do this. If I have time before the deadline, I'll come back and try to make it easier for those that may come into this project after me. However, I believe any other big changes to this application my boss is going to have us rewrite it anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.