7

A user can input a custom :action or choose a featured :action:

<%= f.text_field :action %>
  Or choose a featured challenge:
<%= f.collection_radio_buttons :action, [['Run a Mile','Run a Mile'], ['Drink 16oz of Water','Drink 16oz of Water'], ['Take a Picture','Take a Picture'], ['1 Drink Max','1 Drink Max'], ['See Eiffel Tower','See Eiffel Tower'], ['Write a Book','Write a Book'], ['Skydive','Skydive'], ['Start a Business','Start a Business'], ['No Snooze','No Snooze'], ['Visit All 50 States','Visit All 50 States'], ['Talk to a Stranger','Talk to a Stranger'], ['Try a New Recipe','Try a New Recipe'], ['Media-fast','Media-fast']], :first, :last %>

If a user chooses a featured :action the new challenges/_form is pre-populated with his chosen :action, but now I'd like to take it to the next level with your help!

<%= form_for(@challenge)  do |f| %>
  Challenge: <%= f.text_field :action %>
  Do On: <%= f.collection_check_boxes :committed %>
  Do For: <%= f.number_field :days_challenged %>
<% end %>

How can I pre-populate the other attributes of a featured challenge like, "Do For" or "Do On"?

For example if a user chose the featured :action: 'Run a Mile then I would pre-populate the form with Run a Mile, Mon, Wed, Fri, 30 Days.

AnthonyGalli.com
  • 2,796
  • 5
  • 31
  • 80

1 Answers1

2

You can use simple_form with reform. Reform will give you form object, where you can override methods that will populate your form.

Here is a watered-down example (you will have to adjust it to your case):

class ChallengeForm < Reform::Form
  property :action
  property :committed
  property :days_challenged

  model :challenge

  def commited
    super || action_to_commited_hash[model.action]
  end

  def days_challenged
    super || action_to_days_challenged_hash[model.action]
  end

  def action_to_days_challenged_hash
    {
      'Run a Mile' => 30,
      'Take a Picture' => 12
    }
  end

  def action_to_commited_hash
    {
      'Run a Mile' => ['Mon', 'Wed', 'Fri'],
      'Take a Picture' => ['Tu', 'Thu']
    }
  end
end

super in the methods above will delegate to the model. Note that you are overriding getter methods, and it doesn't affect setters (you can override setters too if you wanted to change form data before writing it).

In your template, instead of

form_for @challenge

you will have:

simple_form_for @form

It's a super common form library for Rails and I can't imagine not using it myself!

Petr Gazarov
  • 3,602
  • 2
  • 20
  • 37
  • Hey okay so I made a folder app/forms then I created `challenge_form.rb` with your code in it. I switched my other form to `simple_form_for @form`. Is this right so far? I can't get it to work from there, neither `action_to_days_challenged_hash` or `action_to_commited_hash` is being set in the secondary form. Only the `action` still sets – AnthonyGalli.com Apr 09 '16 at 22:41
  • HTML Output: `Do For: ` I don't if that's helpful. – AnthonyGalli.com Apr 09 '16 at 22:50
  • Seems right. Are you passing the model to the form as described in reform readme? https://github.com/apotonick/reform (Sorry, I should have specified that I'm really talking about `simple_form` + `reform` usage) - updated my answer. – Petr Gazarov Apr 10 '16 at 00:17
  • No problem. Still a little confused by it. Sorry. So I added the gem `reform-rails` & the gem `reform`. I then created initializers/reform.rb and added `require "reform/form/dry" Reform::Form.class_eval do feature Reform::Form::Dry end`. But I keep getting the error `uninitialized constant Reform::Form (NameError) ` even though I ran `bundle install` Also do I add anything else to challenges_controller or challenge.rb? – AnthonyGalli.com Apr 10 '16 at 16:20
  • Hm, that's weird. And you are definitely not running spring? In the controller you would initialize the form and pass it to the template `@form = ChallengeForm.new(@challenge)` – Petr Gazarov Apr 11 '16 at 14:38
  • Yea not using spring. Do you know how I could initialize in the controller? Maybe that's the trick like create some sort of method in there? Here was my attempt: `before_action :populate_challenge, only: [:create]` and then in the create action: `def populate_challenge(challenge) require "reform/form/dry" Reform::Form.class_eval do feature Reform::Form::Dry end end` I updated the question so you can see what my controller looks like. Thanks for the help! – AnthonyGalli.com Apr 11 '16 at 18:08
  • @AnthonyGalli.com Not sure I'm following your controller logic - is `create` a GET action? Calling `@form.validate(params)` will update form fields with data and `@form.save` will save the challenge model. There are some good docs here: https://github.com/apotonick/reform#the-api – Petr Gazarov Apr 13 '16 at 04:40
  • I think the best place for the contents of `populate_challenge` is in initializers. I'm using `reform` version `1.2.6`, so I don't need the `reform-rails` gem. I have just the following statement in my `initializers/reform.rb`: `Reform::Form.reform_2_0!`. However I think this line is not necessary in latest version of `reform`, as per here: https://github.com/apotonick/reform/blob/master/CHANGES.md – Petr Gazarov Apr 13 '16 at 04:46
  • Yea that got rid of the initializers problem :] Now I've been struggling with setup. I guess because I might be doing it a little wacky with the GET action in `def create`. I'm sure your answer will help people with this general problem, but I decided to create another question that more specifically addresses my problem if you want to continue the conversation over there with me :] http://stackoverflow.com/questions/36667978/how-to-use-reform-to-prepopulate-for-featured-objects – AnthonyGalli.com Apr 16 '16 at 18:26