Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pattern matching APIs for records and relations. #45070

Closed
wants to merge 1 commit into from

Conversation

kddnewton
Copy link
Contributor

This provides the Ruby 2.7+ pattern matching interface for Active Record
records and relations. It allows the user to pattern match against
attributes and associations on records through a hash pattern. It also
allows the user to pattern match against relations through an array pattern.

class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

post = Post.new(title: "Welcome!", comments: [Comment.new(body: "Thanks!")])
post => { title: "Welcome!", comments: [Comment[body:]] }
body # => "Thanks!"

@kddnewton
Copy link
Contributor Author

cc @gmcgibbon since you kindly merged the last one

This provides the Ruby 2.7+ pattern matching interface for Active Record
records and relations. It allows the user to pattern match against
attributes and associations on records through a hash pattern. It also
allows the user to pattern match against relations through an array pattern.

```ruby
class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

post = Post.new(title: "Welcome!", comments: [Comment.new(body: "Thanks!")])
post => { title: "Welcome!", comments: [Comment[body:]] }
body # => "Thanks!"
```

*Kevin Newton*
Copy link
Member

@gmcgibbon gmcgibbon left a comment

Choose a reason for hiding this comment

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

LGTM. Could you please fix the merge conflicts?

@ezekg
Copy link
Contributor

ezekg commented Aug 10, 2022

What's the status of this? Still blocked? I've been using this in production and it's working great.

@rafaelfranca
Copy link
Member

Here you can read the status of this #45553 (comment)

@ezekg
Copy link
Contributor

ezekg commented Aug 10, 2022

@rafaelfranca, I saw that but @kddnewton hasn't gotten a response in nearly a month. I agree with his reasoning.

Would hate to see this get lost. I don't see a problem with the current API.

@rafaelfranca
Copy link
Member

We don't need to rush a decision here. Rails 7.1 isn't due any time soon and this feature would only be release in Rails 7.1. Rushing a making the wrong decision will just cause trouble for us maintainers, so it is better to make sure we have considered all possibilities.

@ezekg
Copy link
Contributor

ezekg commented Aug 10, 2022

Understood, @rafaelfranca. Is there a location where this discussion is taking place?

@kddnewton
Copy link
Contributor Author

In the meantime, I've released a gem https://github.com/kddnewton/rails-pattern_matching that encapsulates this pattern. Folks can maybe use that to prototype/test what they think is the right approach. Hopefully that will help aid in a decision.

# person = Person.new
# person.name = "Bob"
# greeting_for(person) # => "Welcome, stranger!"
def deconstruct_keys(keys)
Copy link
Contributor

Choose a reason for hiding this comment

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

(Sorry, just passing by.)

Note that keys might be nil, if somebody does this:

case person
in name: 'Mary', **attributes
  Rails.logger.info "Mary logged in. Currently set of attrs are: #{attributes}"
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I handled that in the gem I mentioned. I wasn't sure if this PR was moving anywhere so I'm waiting to hear on this.

Copy link
Contributor

@pboling pboling Mar 4, 2024

Choose a reason for hiding this comment

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

I'm not doing anything fancy, just destructuring rightward assignment, and the gem is working great for that purpose!

    rec = MyRecord.find(id)

    # Destructuring Rightward Assignment
    # See: https://www.fullstackruby.dev/ruby-3-fundamentals/2021/01/06/everything-you-need-to-know-about-destructuring-in-ruby-3/
    rec => {
      organization_id:,
      group_id:,
      source_id:,
      patch_id:,
      report_id:,
    }
    # and now I have all those local variables to work with, pulled directly from my records' attributes.

I have noticed that it only works with true attributes, so if I create an accessor method I can't pull that value through (yet).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pboling that's expected. If you have any other feedback on the gem though feel free to open an issue on the gem repo itself

@kddnewton
Copy link
Contributor Author

For my own work-tracking purposes I'm going to close this PR, but I will continue to maintain the gem. If there comes a time where rails would like to consider pattern matching, give me a shout!

@kddnewton kddnewton closed this Mar 4, 2024
@kddnewton kddnewton deleted the pattern-matching-ar branch March 4, 2024 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants