Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 47 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Consider an example where you want to create/update a conference that can have m
```ruby
class ConferenceForm < ActiveForm::Base
self.main_model = :conference

attributes :name, :city

validates :name, :city, presence: true
end
```
Expand Down Expand Up @@ -223,11 +223,11 @@ Use `fields_for` in a Rails environment to correctly setup the structure of para
<%= form_for @conference_form |f| %>
<%= f.text_field :name %>
<%= f.text_field :city %>

<%= f.fields_for :speakers do |s| %>
<%= s.text_field :name %>
<%= s.text_field :occupation %>

<%= s.fields_for :presentation do |p| %>
<%= p.text_field :topic %>
<%= p.text_field :duration %>
Expand Down Expand Up @@ -323,6 +323,49 @@ And `app/views/conferences/_presentation_fields.html.erb` would be:
</div>
```

## Plain Old Ruby Object Forms

ActiveForm also can accept `ActiveModel::Model` instances as a model.

Let's define the Feeback class class with `ActiveModel::Model` that will be used for customer's feedback:

```ruby
class Feedback
include ActiveModel::Model

attr_accessible :name, :body, :email

def save
FeedbackMailer.send_email(email, name, body)
end
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not override save 😄

What do you think of this?

after_save :mail_feedback

private
  def mail_feedback
    FeedbackMailer.mail_feedback(email, name, body).deliver_later
  end

(I also changed the mailer so it's closer to the actual Action Mailer API in Rails 4.2.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActiveModel::Model doesn't have any save method or callbacks by default.

end
```

The form should look like this.

```ruby
class FeedbackForm < ActiveForm::Base
attributes :name, :body, :email, required: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to set main_model like so: self.main_model = :feedback.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK the PR with auto-detection of main_model was merged recently.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right you are 😄

end
```

And then in controller:

```ruby
class FeedbacksController
def create
feedback = Feedback.new
@feedback_form = FeedbackForm.new(feedback)
@feedback_form.submit(feedback_params)

if @feedback_form.save
head :ok
else
render json: @feedback_form.errors
end
end
```

## Demos

You can find a list of applications using this gem in this repository: https://github.com/m-Peter/nested-form-examples .
Expand Down
14 changes: 14 additions & 0 deletions test/forms/poro_form_fixture.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class Poro
include ActiveModel::Model

attr_accessor :name, :city

def save
true
end
end

class PoroFormFixture < ActiveForm::Base
self.main_model = :conference
attributes :name, :city, required: true
end
41 changes: 41 additions & 0 deletions test/forms/poro_form_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'test_helper'
require_relative 'poro_form_fixture'

class PoroFormTest < ActiveSupport::TestCase
include ActiveModel::Lint::Tests

setup do
@poro = Poro.new
@form = PoroFormFixture.new(@poro)
@model = @form
end


test "main form validates itself" do
params = {
name: "Euruco",
city: "Athens"
}

@form.submit(params)

assert @form.valid?

@form.submit({ name: nil, city: nil })

assert_not @form.valid?
assert_includes @form.errors[:name], "can't be blank"
assert_includes @form.errors[:city], "can't be blank"
end

test "save works" do
params = {
name: "Euruco",
city: "Athens"
}

@form.submit(params)

assert @form.save
end
end