When building a web application using Ruby on Rails, one of the most important concepts to understand is the params object. The params object is a hash-like object that contains all of the parameters passed to a Rails controller action, including form data, query parameters, and route parameters. In this blog post, we'll discuss the basics of using params in a Rails application.

Basic Usage

        In a Rails controller action, the params object is available as a method call, and can be used to access the parameters passed to the action. For example, if we have a route that maps to the show action of a PostsController, we can access the id parameter like this:

class PostsController < ApplicationController
  def show
    post = Post.find(params[:id])
    # ...
  end
end

        In this example, we're using the find method of the Post model to find a post by its id parameter. The params object is accessed like a hash, with the parameter name as the key.

        We can also use the params object to access form data submitted in a POST request. For example, if we have a form that submits a title and body parameter, we can access those parameters like this:

class PostsController < ApplicationController
  def create
    post = Post.new(params.require(:post).permit(:title, :body))
    # ...
  end
end

        In this example, we're using the require and permit methods to allow only the title and body parameters to be passed to the Post model's new method. The require method ensures that the post parameter is present, while the permit method whitelists the allowed parameters.

Handling Missing Parameters

        When accessing parameters using the params object, it's important to handle cases where a parameter is missing. If a required parameter is missing, Rails will raise a ActionController::ParameterMissing exception. For example, if we try to access the id parameter of a route that doesn't have an id parameter, we'll get an exception:

class PostsController < ApplicationController
  def show
    post = Post.find(params[:id])
    # ...
  end
end

        If the route doesn't include an id parameter, this code will raise an exception. To handle this case, we can use the fetch method of the params object, which allows us to specify a default value if the parameter is missing:

class PostsController < ApplicationController
  def show
    post = Post.find(params.fetch(:id, 1))
    # ...
  end
end

        In this example, we're using the fetch method to specify a default value of 1 if the id parameter is missing.

Nested Parameters

        In many cases, you may need to work with nested parameters in a Rails application. For example, if you have a form that includes fields for multiple models, you might need to use nested parameters to organize the form data. Here's an example of how you might handle nested parameters for a blog post form that includes fields for both the post and the author:

class PostsController < ApplicationController
  def create
    post_params = params.require(:post).permit(:title, :body, author_attributes: [:name, :email])
    post = Post.new(post_params)
    # ...
  end
end

        In this example, we're using the require and permit methods to allow the title, body, and author_attributes parameters to be passed to the Post model's new method. The author_attributes parameter is a nested hash that includes the name and email attributes for the author.

Strong Parameters

        In Rails 4 and later versions, the params object is designed to work with strong parameters, which provide an extra layer of security for your application by whitelisting the parameters that can be passed to a model. By default, Rails will raise an exception if any parameters that are not explicitly whitelisted are passed to a model's new or update_attributes method. Here's an example of how you might use strong parameters in a controller action:

class PostsController < ApplicationController
  def create
    post_params = params.require(:post).permit(:title, :body)
    post = Post.new(post_params)
    # ...
  end

  def update
    post_params = params.require(:post).permit(:title, :body)
    post = Post.find(params[:id])
    post.update_attributes(post_params)
    # ...
  end
end

        In these examples, we're using the require and permit methods to whitelist the title and body parameters that can be passed to the Post model's new and update_attributes methods. This ensures that only the parameters that we expect can be passed to the model, reducing the risk of security vulnerabilities like mass assignment attacks.

Query Parameters

        In addition to form data and route parameters, the params object can also be used to access query parameters in a Rails application. Query parameters are passed in the URL, after a ? character, and can be accessed using the params object like this:

class PostsController < ApplicationController
  def index
    @posts = Post.where(published: params[:published])
    # ...
  end
end

        In this example, we're using the where method of the Post model to find all posts that match a certain value for the published attribute. The value is passed as a query parameter in the URL, like ?published=true. By accessing the published parameter using the params object, we can use it to filter the results of the query.

Conclusion

        The params object is a powerful tool for working with parameters in a Rails controller action. By understanding how to use the params object to access form data, query parameters, and route parameters, you can build robust and flexible Rails applications. However, it's important to handle missing parameters gracefully, using methods like fetch or require, to ensure that your application is robust and secure.