The project is in a healthy, maintained state
Pattern matching for Rails applications
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

rails-pattern_matching

Build Status Gem

This gem provides the pattern matching interface for ActionController::Parameters, ActiveModel::AttributeMethods, ActiveRecord::Base, and ActiveRecord::Relation.

That means it allows you to write code using pattern matching within your Rails applications like the following examples:

# app/models/post.rb
class Post < ApplicationRecord
  has_many :comments
end

# app/models/comment.rb
class Comment < ApplicationRecord
  belongs_to :post
end

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def update
    @post = Post.find(params[:id])

    case params.require(:post).permit(:title, :body, :published)
    in { published: true } if !can_publish?(@post, current_user)
      # Here we are matching against a single parameter with a guard clause.
      # This allows us to express both the value check and the authorization
      # check in a single line.
      render :edit, alert: "You are not authorized to publish this post"
    in permitted if @post.update(permitted)
      # Here we are grabbing the entire set of parameters and then using it to
      # update the post. If the update succeeds, this branch will be taken.
      redirect_to @post, notice: "Post was successfully updated"
    else
      # Here we are providing a default in case none of the above match. This
      # will be taken if the update fails, and presumably the view will render
      # appropriate error messages.
      render :edit
    end
  end
end

# app/helpers/posts_helper.rb
module PostsHelper
  def comment_header_for(post)
    case post
    in { comments: [] }
      # Here we're matching against an attribute on the post that is an
      # association. It will go through the association and then match against
      # the records in the relation.
      "No comments yet"
    in { user_id:, comments: [*, { user_id: ^user_id }, *] }
      # Here we're searching for a comment that has the same user_id as the
      # post. We can do this with the "find" pattern. This syntax is all baked
      # into Ruby, so we don't have to do anything other than define the
      # requisite deconstruct methods that are used by the pattern matching.
      "Author replied"
    in { comments: [{ user: { name: } }] }
      # Here we're extracting the first comment out of the comments association
      # and using its associated user's name in the header.
      "One comment from #{name}"
    in { comments: }
      # Here we provide a default in case none of the above match. Since we have
      # already matched against an empty array of comments and a single element
      # array, we know that there are at least two comments. We can get the
      # length of the comments association by capturing the comments association
      # in the pattern itself and then using it.
      "#{comments.length} comments"
    end
  end
end

Installation

Add this line to your application's Gemfile:

gem "rails-pattern_matching"

And then execute:

$ bundle

Or install it yourself as:

$ gem install rails-pattern_matching

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/kddnewton/rails-pattern_matching.

License

The gem is available as open source under the terms of the MIT License.