How to default collection_check_boxes to checked?
Asked Answered
S

2

5

I have this line that I'm trying to default to checked <%= f.collection_check_boxes :committed, checked, Date::ABBR_DAYNAMES, :downcase, :to_s, %>

In db t.text "committed".

I tried variations of checked & true, but maybe I overlooked something.

Here's the Gist of it.

Sallyanne answered 1/8, 2015 at 20:40 Comment(8)
When you say in db t.text "committed" - which table are you talking about? Can you briefly describe the models you're working on?Gynous
Agreed. The attribute must be associated with a model. Usually, I find it best for collection check boxes to be from another table, when you are looking for pre-checked items. Because then in your controller you can do nested attributesRumelia
@Gynous I updated the question with a gist. Hopefully that gives a better idea because I'm not quite sure what your asking.Sallyanne
@HunterStevens thanks for the details! I updated the question with a gist.Sallyanne
Is this a form for new habit, update one, or both?Gynous
Please put some of the most relevant code blocks in the question itself. Also please put some context. What have you tried? What are the errors? What do you expect? Are you using any form gems? What version of rails?Rumelia
@Gynous this is a new form to start. Then the user can leave them or uncheck them.Sallyanne
Are you using Postgres or MySQL?Gynous
G
6

You are using a form_for, so that f is a form builder. This means that it is bound to the object you initialized it with, let's call it @habit. Since you're calling collection_check_boxes on the form builder, it will do something like @habit.send(:commit) to consult whether or not it should have the check box checked, and currently (apparently) it is not. In other words, if you want to use form_for you need to have this "everything is checked" fact represented in the model itself.

Now I am not sure what your model layer looks like, so I'll address a few scenarios. If you have a has_and_belongs_to_many relationship like this:

class Habit < ActiveRecord::Base
  has_and_belongs_to_many :committed_days
end

class CommittedDay < ActiveRecord::Base
  has_and_belongs_to_many :habits
  # let's assume it has the columns :id and :name
  # also, let's assume the n:m table committed_days_habits exists
end

Then I think the easiest way is in the controller itself do something like this:

def new
  @habit = Habit.new
  @habit.committed_day_ids = CommittedDay.all.map(&:id)
end

And in your ERB do:

<%= f.collection_check_boxes(:committed_day_ids, CommittedDay.all, :id, :name)

Now, it might be an overkill to do this with a has-and-belongs-to-many, especially with days of week (it means the CommittedDay table has 7 records, one for each day, which is kinda awkward). So you could also consider simply serializing an array of days of week into the db, and then just make sure the default for that column contains all of them.

The ERB will be similar to what you wrote:

<%= f.collection_check_boxes :committed, Date::ABBR_DAYNAMES, :downcase, :to_s %>

If you're using Postgres your class can be simply:

class Habit < ActiveRecord::Base
end

And the serialization code would be in the migration:

# downcase is used since in the ERB you are using :downcase for the id method
t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase), array: true

If you are not using Postgres, you can use Rails serialization which is DB agnostic:

class Habit < ActiveRecord::Base
  serialize :committed, Array
end

And then your migration would look like this:

t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase).to_yaml
Gynous answered 1/8, 2015 at 21:20 Comment(2)
Run rails g migration name_of_migration and edit the file.Gynous
Awesome! You are a live saver.Fausta
P
12

Here is a quick answer on how to add checked as the default to the collection_check_boxes form helper since it took me some time to figure it out. Break it into a block and you can set checked and add classes. More info at http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_check_boxes.

<%= f.collection_check_boxes(:author_ids, Author.all, :id, :name) do |b| %>
  <%= b.label(class: "check_box") { b.check_box(checked: true, class: "add_margin") + b.text } %>
<% end %>
Perverted answered 28/3, 2017 at 2:25 Comment(0)
G
6

You are using a form_for, so that f is a form builder. This means that it is bound to the object you initialized it with, let's call it @habit. Since you're calling collection_check_boxes on the form builder, it will do something like @habit.send(:commit) to consult whether or not it should have the check box checked, and currently (apparently) it is not. In other words, if you want to use form_for you need to have this "everything is checked" fact represented in the model itself.

Now I am not sure what your model layer looks like, so I'll address a few scenarios. If you have a has_and_belongs_to_many relationship like this:

class Habit < ActiveRecord::Base
  has_and_belongs_to_many :committed_days
end

class CommittedDay < ActiveRecord::Base
  has_and_belongs_to_many :habits
  # let's assume it has the columns :id and :name
  # also, let's assume the n:m table committed_days_habits exists
end

Then I think the easiest way is in the controller itself do something like this:

def new
  @habit = Habit.new
  @habit.committed_day_ids = CommittedDay.all.map(&:id)
end

And in your ERB do:

<%= f.collection_check_boxes(:committed_day_ids, CommittedDay.all, :id, :name)

Now, it might be an overkill to do this with a has-and-belongs-to-many, especially with days of week (it means the CommittedDay table has 7 records, one for each day, which is kinda awkward). So you could also consider simply serializing an array of days of week into the db, and then just make sure the default for that column contains all of them.

The ERB will be similar to what you wrote:

<%= f.collection_check_boxes :committed, Date::ABBR_DAYNAMES, :downcase, :to_s %>

If you're using Postgres your class can be simply:

class Habit < ActiveRecord::Base
end

And the serialization code would be in the migration:

# downcase is used since in the ERB you are using :downcase for the id method
t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase), array: true

If you are not using Postgres, you can use Rails serialization which is DB agnostic:

class Habit < ActiveRecord::Base
  serialize :committed, Array
end

And then your migration would look like this:

t.text :committed, default: Date::ABBR_DAYNAMES.map(&:downcase).to_yaml
Gynous answered 1/8, 2015 at 21:20 Comment(2)
Run rails g migration name_of_migration and edit the file.Gynous
Awesome! You are a live saver.Fausta

© 2022 - 2024 — McMap. All rights reserved.