# ActionArgs [![Build Status](https://travis-ci.org/asakusarb/action_args.svg?branch=master)](https://travis-ci.org/asakusarb/action_args) Controller action arguments parameterizer for Rails 4.1+ ## What is this? ActionArgs is a Rails plugin that extends your controller action methods to allow you to specify arguments of interest in the method definition for any action. - in short, Merbish. ## The Controllers Having the following controller code: ```ruby class HogeController < ApplicationController def fuga(piyo) render :text => piyo end end ``` Hitting "/hoge/fuga?piyo=foo" will call `fuga('foo')` and output 'foo'. This allows you to explicitly state which members of the `params` Hash are used in your controller actions. ## Method parameter types in Ruby, and how ActionArgs handles parameters ### Required Parameters (:req) Method parameters that you specify are required. If a key of the same name does not exist in the params Hash, ActionContrller::BadRequest is raised. In this `show` action, ActionArgs will require that `id` parameter is provided. ```ruby class UsersController < ApplicationController # the `id` parameter is mandatory def show(id) @user = User.find id end end ``` ### Optional Parameters (:opt) Default parameter values are assigned in the standard way. Parameters with a default value will not require a matching item in the `params` Hash. ```ruby class UsersController < ApplicationController # the `page` parameter is optional def index(page = nil) @users = User.page(page).per(50) end end ``` ### Keyword Argument (:key) If you think this Ruby 2.0 syntax reads better, you can choose this style for defining your action methods. This just works in the same way as :opt here. ```ruby class UsersController < ApplicationController # the `page` parameter is optional def index(page: nil) @users = User.page(page).per(50) end end ``` ### Required Keyword Argument (:keyreq) :keyreq is the required version of :key, which was introduced in Ruby 2.1. You can use this syntax instead of :req. ```ruby class CommentsController < ApplicationController def create(post_id:, comment:) post = Post.find post_id if post.create comment ... end end ``` ### StrongParameters - permit ActionArgs plays very nice with Rails 4 StrongParameters. 1. Inline declaration Hashes simply respond to the StrongParameters' `permit` method. ```ruby class UsersController < ApplicationController def create(user) @user = User.new(user.permit(:name, :age)) ... end end ``` 2. Declarative white-listing ActionArgs also provides a declarative `permits` method for controller classes. Use this to keep your `permit` calls DRY in a comprehensible way. ```ruby class UsersController < ApplicationController # white-lists User model's attributes permits :name, :age # the given `user` parameter would be automatically permitted by ActionArgs def create(user) @user = User.new(user) end end ``` By default, action_args deduces the target model name from the controller name. For example, the `permits` call in `UsersController` expects the model name to be `User`. If this is not the case, you can specify the :model_name option: ```ruby class MembersController < ApplicationController # white-lists User model's attributes permits :name, :age, model_name: 'User' end ``` ## Filters ActionArgs works in filters, in the same way as it works in controller actions. ```ruby class UsersController < ApplicationController before_action :set_user, only: :show def show end private # `params[:id]` will be dynamically assigned to the method parameter `id` here def set_user(id) @user = User.find(id) end end ``` ## The Scaffold Generator ActionArgs provides a custom scaffold controller generator that overwrites the default scaffold generator. Thus, by hitting the scaffold generator command like this: ```sh % rails g scaffold user name age:integer email ``` The following elegant controller code will be generated: ```ruby class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update, :destroy] permits :name, :age, :email # GET /users def index @users = User.all end # GET /users/1 def show end # GET /users/new def new @user = User.new end # GET /users/1/edit def edit end # POST /users def create(user) @user = User.new(user) if @user.save redirect_to @user, notice: 'User was successfully created.' else render action: 'new' end end # PUT /users/1 def update(user) if @user.update_attributes(user) redirect_to @user, notice: 'User was successfully updated.' else render action: 'edit' end end # DELETE /users/1 def destroy @user.destroy redirect_to users_url end private # Use callbacks to share common setup or constraints between actions. def set_user(id) @user = User.find(id) end end ``` You may notice that * There are no globalish `params` reference * It's quite easy to comprehend what's the actual input value for each action * You may write the unit test code as if the actions are just normal Ruby methods ## Supported versions * Ruby 2.0.0, 2.1.x, 2.2.x, 2.3.x, 2.4.x, 2.5.0 (trunk), JRuby, & Rubinius with 2.0+ mode * Rails 4.1.x, 4.2.x, 5.0, 5.1 (edge) Please use Version 1.5.4 for Rails 4.0.x. ## Installation Put this line in your Gemfile: ```ruby gem 'action_args' ``` Then bundle: ```sh % bundle ``` ## Notes ### Plain Old Action Methods Of course you still can use both Merbish style and plain old Rails style action methods even if this plugin is loaded. `params` parameter is still alive as well. That means, this plugin won't break any existing controller API. ### Argument Naming Convention Each action method parameter name corresponds to `params` key name. For example, the following beautifully written nested `show` action works perfectly (this might not be a very good example of effective querying, but that's another story). ```ruby Rails.application.routes.draw do resources :authors do resources :books end end class BooksController < ApplicationController # GET /authors/:author_id/books/:id def show(author_id, id) @book = Author.find(author_id).books.find(id) end ... end ``` ### Default parameter values You are of course able to specify default values for action parameters such as: ```ruby class BooksController < ApplicationController def index(author_id = nil, page = 1) ... end end ``` However, due to some implementation reasons, the `page` variable will be actually defaulted to nil when `page` parameter was not given. In order to provide default parameter values in perfect Ruby manner, we recommend you to use the Ruby 2.0 "keyword arguments" syntax instead. ```ruby class BooksController < ApplicationController def index(author_id: nil, page: 1) ... end end ``` This way, the `page` parameter will be defaulted to 1 as everyone might expect. ## Copyright Copyright (c) 2011- Asakusa.rb. See MIT-LICENSE for further details.