<commit_before># ActiveInteraction

[![Gem Version][]](https://badge.fury.io/rb/active_interaction)
[![Build Status][]](https://travis-ci.org/orgsync/active_interaction)
[![Coverage Status][]](https://coveralls.io/r/orgsync/active_interaction)
[![Code Climate][]](https://codeclimate.com/github/orgsync/active_interaction)
[![Dependency Status][]](https://gemnasium.com/orgsync/active_interaction)

At first it seemed alright. A little business logic in a controller or model
wasn't going to hurt anything. Then one day you wake up and you're surrounded
by fat models and unweildy controllers. Curled up and crying in the
corner, you can't help but wonder how it came to this.

Take back control. Slim down models and wrangle monstrous controller methods
with ActiveInteraction.

## Installation

This project uses [semantic versioning][].

Add it to your Gemfile:

~~~ rb
gem 'active_interaction', '~> 0.1.1'
~~~

And then execute:

~~~ sh
$ bundle
~~~

Or install it yourself as:

~~~ rb
$ gem install active_interaction
~~~

## What do I get?

ActiveInteraction::Base lets you create interaction models. These models ensure
that certain options are provided and that those options are in the format you
want them in. If the options are valid it will call `execute`, store the return
value of that method in `result`, and return an instance of your ActiveInteraction::Base
subclass. Let's looks at a simple example:

~~~ rb
# Define an interaction that signs up a user.
class UserSignup < ActiveInteraction::Base
  # required
  string :email, :name

  # optional
  boolean :newsletter_subscribe, allow_nil: true

  # ActiveRecord validations
  validates :email, format: EMAIL_REGEX

  # The execute method is called only if the options validate. It does your
  # business action. The return value will be stored in `result`.
  def execute
    user = User.create!(email: email, name: name)
    NewsletterSubscriptions.create(email: email, user_id: user.id) if newsletter_subscribe
    UserMailer.async(:deliver_welcome, user.id)
    user
  end
end

# In a controller action (for instance), you can run it:
def new
  @signup = UserSignup.new
end

def create
  @signup = UserSignup.run(params[:user])

  # Then check to see if it worked:
  if @signup.valid?
    redirect_to welcome_path(user_id: signup.result.id)
  else
    render action: :new
  end
end
~~~

You may have noticed that ActiveInteraction::Base quacks like ActiveRecord::Base.
It can use validations from your Rails application and check option validity with
`valid?`. Any errors are added to `errors` which works exactly like an ActiveRecord
model.

## How do I call an interaction?

There are two way to call an interaction. Given UserSignup, you can do this:

~~~ rb
outcome = UserSignup.run(params)
if outcome.valid?
  # Do something with outcome.result...
else
  # Do something with outcome.errors...
end
~~~

Or, you can do this:

~~~ rb
result = UserSignup.run!(params)
# Either returns the result of execute,
# or raises ActiveInteraction::InteractionInvalid
~~~

## What can I pass to an interaction?

Interactions only accept a Hash for `run` and `run!`.

~~~ rb
# A user comments on an article
class CreateComment < ActiveInteraction::Base
  model :article, :user
  string :comment

  validates :comment, length: {maximum: 500}

  def execute; ...; end
end

def somewhere
  outcome = CreateComment.run(
    comment: params[:comment],
    article: Article.find(params[:article_id]),
    user: current_user
  )
end
~~~

## How do I define an interaction?

1. Subclass ActiveInteraction::Base

    ~~~ rb
    class YourInteraction < ActiveInteraction::Base
      # ...
    end
    ~~~

2. Define your attributes:

    ~~~ rb
    string :name, :state
    integer :age
    boolean :is_special
    model :account
    array :tags, allow_nil: true do
      string
    end
    hash :prefs, allow_nil: true do
      boolean :smoking
      boolean :view
    end
    date :arrives_on, default: Date.today
    date :departs_on, default: Date.tomorrow
    ~~~

3. Use any additional validations you need:

    ~~~ rb
    validates :name, length: {maximum: 10}
    validates :state, inclusion: {in: %w(AL AK AR ... WY)}
    validate arrives_before_departs

    private

    def arrive_before_departs
      if departs_on <= arrives_on
        errors.add(:departs_on, 'must come after the arrival time')
      end
    end
    ~~~

4. Define your execute method. It can return whatever you like:

    ~~~ rb
    def execute
      record = do_thing(...)
      # ...
      record
    end
    ~~~

A full list of methods can be found [here](http://www.rubydoc.info/github/orgsync/active_interaction/master/ActiveInteraction/Base).

## Credits

This project was inspired by the fantastic work done in [Mutations][].

[build status]: https://travis-ci.org/orgsync/active_interaction.png
[code climate]: https://codeclimate.com/github/orgsync/active_interaction.png
[coverage status]: https://coveralls.io/repos/orgsync/active_interaction/badge.png
[dependency status]: https://gemnasium.com/orgsync/active_interaction.png
[gem version]: https://badge.fury.io/rb/active_interaction.png
[mutations]: https://github.com/cypriss/mutations
[semantic versioning]: http://semver.org<commit_msg>fix parsing language for code snippet and indent level on code blocks in lists<commit_after># ActiveInteraction

[![Gem Version][]](https://badge.fury.io/rb/active_interaction)
[![Build Status][]](https://travis-ci.org/orgsync/active_interaction)
[![Coverage Status][]](https://coveralls.io/r/orgsync/active_interaction)
[![Code Climate][]](https://codeclimate.com/github/orgsync/active_interaction)
[![Dependency Status][]](https://gemnasium.com/orgsync/active_interaction)

At first it seemed alright. A little business logic in a controller or model
wasn't going to hurt anything. Then one day you wake up and you're surrounded
by fat models and unweildy controllers. Curled up and crying in the
corner, you can't help but wonder how it came to this.

Take back control. Slim down models and wrangle monstrous controller methods
with ActiveInteraction.

## Installation

This project uses [semantic versioning][].

Add it to your Gemfile:

~~~ rb
gem 'active_interaction', '~> 0.1.1'
~~~

And then execute:

~~~ sh
$ bundle
~~~

Or install it yourself as:

~~~ sh
$ gem install active_interaction
~~~

## What do I get?

ActiveInteraction::Base lets you create interaction models. These models ensure
that certain options are provided and that those options are in the format you
want them in. If the options are valid it will call `execute`, store the return
value of that method in `result`, and return an instance of your ActiveInteraction::Base
subclass. Let's looks at a simple example:

~~~ rb
# Define an interaction that signs up a user.
class UserSignup < ActiveInteraction::Base
  # required
  string :email, :name

  # optional
  boolean :newsletter_subscribe, allow_nil: true

  # ActiveRecord validations
  validates :email, format: EMAIL_REGEX

  # The execute method is called only if the options validate. It does your
  # business action. The return value will be stored in `result`.
  def execute
    user = User.create!(email: email, name: name)
    NewsletterSubscriptions.create(email: email, user_id: user.id) if newsletter_subscribe
    UserMailer.async(:deliver_welcome, user.id)
    user
  end
end

# In a controller action (for instance), you can run it:
def new
  @signup = UserSignup.new
end

def create
  @signup = UserSignup.run(params[:user])

  # Then check to see if it worked:
  if @signup.valid?
    redirect_to welcome_path(user_id: signup.result.id)
  else
    render action: :new
  end
end
~~~

You may have noticed that ActiveInteraction::Base quacks like ActiveRecord::Base.
It can use validations from your Rails application and check option validity with
`valid?`. Any errors are added to `errors` which works exactly like an ActiveRecord
model.

## How do I call an interaction?

There are two way to call an interaction. Given UserSignup, you can do this:

~~~ rb
outcome = UserSignup.run(params)
if outcome.valid?
  # Do something with outcome.result...
else
  # Do something with outcome.errors...
end
~~~

Or, you can do this:

~~~ rb
result = UserSignup.run!(params)
# Either returns the result of execute,
# or raises ActiveInteraction::InteractionInvalid
~~~

## What can I pass to an interaction?

Interactions only accept a Hash for `run` and `run!`.

~~~ rb
# A user comments on an article
class CreateComment < ActiveInteraction::Base
  model :article, :user
  string :comment

  validates :comment, length: {maximum: 500}

  def execute; ...; end
end

def somewhere
  outcome = CreateComment.run(
    comment: params[:comment],
    article: Article.find(params[:article_id]),
    user: current_user
  )
end
~~~

## How do I define an interaction?

1. Subclass ActiveInteraction::Base

   ~~~ rb
   class YourInteraction < ActiveInteraction::Base
     # ...
   end
   ~~~

2. Define your attributes:

   ~~~ rb
   string :name, :state
   integer :age
   boolean :is_special
   model :account
   array :tags, allow_nil: true do
     string
   end
   hash :prefs, allow_nil: true do
     boolean :smoking
     boolean :view
   end
   date :arrives_on, default: Date.today
   date :departs_on, default: Date.tomorrow
   ~~~

3. Use any additional validations you need:

   ~~~ rb
   validates :name, length: {maximum: 10}
   validates :state, inclusion: {in: %w(AL AK AR ... WY)}
   validate arrives_before_departs

   private

   def arrive_before_departs
     if departs_on <= arrives_on
       errors.add(:departs_on, 'must come after the arrival time')
     end
   end
   ~~~

4. Define your execute method. It can return whatever you like:

   ~~~ rb
   def execute
     record = do_thing(...)
     # ...
     record
   end
   ~~~

A full list of methods can be found [here](http://www.rubydoc.info/github/orgsync/active_interaction/master/ActiveInteraction/Base).

## Credits

This project was inspired by the fantastic work done in [Mutations][].

[build status]: https://travis-ci.org/orgsync/active_interaction.png
[code climate]: https://codeclimate.com/github/orgsync/active_interaction.png
[coverage status]: https://coveralls.io/repos/orgsync/active_interaction/badge.png
[dependency status]: https://gemnasium.com/orgsync/active_interaction.png
[gem version]: https://badge.fury.io/rb/active_interaction.png
[mutations]: https://github.com/cypriss/mutations
[semantic versioning]: http://semver.org
{'fraction_non_alphanumeric': 0.10204664445502142, 'fraction_numerical': 0.0022846263683960017, 'mean_word_length': 3.927767354596623, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 22, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2902918', 'n_tokens_mistral': 3236, 'n_tokens_neox': 3119, 'n_words': 1134}