1

I have a Rails model, which is using the str_enum gem.

I'm building a generator which reads the models and creates pages for them, and so I'd like to be able to understand what str_enums are attached to a model.

For example

class User < ApplicationRecord
  str_enum :email_frequency, %i[every daily weekly], default: 'every'
end

Ideally, I'd like to be able to query the User model and understand there is a str_enum attached to email_frequency, with values of every, daily & weekly.

Once I can understand there is a str_enum attached to a given field, I can pluralize the field and get the values:

irb(main):004:0> User.email_frequencies
=> ["every", "daily", "weekly"]

The question has also be asked over here and the suggestion is to use Module#prepend. I'm familiar with prepend to conditionally insert methods into a model.

How can I use it for this problem?

EDIT

This is quite simple with validations, for example: get validations from model

port5432
  • 5,889
  • 10
  • 60
  • 97

2 Answers2

5

If I understand your question correctly is that you wanna get all column that has attached with enum string. If so you can override the gem method like this

# lib/extenstions/str_enum.rb

module Extensions
  module StrEnum
    module ClassMethods
      def str_enum(column, *args)
        self.str_enums << column.to_s.pluralize
        super
      end
    end

    def self.prepended(base)
      class << base
        mattr_accessor :str_enums
        self.str_enums = []
        prepend ClassMethods
      end
    end
  end
end

In the User model

prepend Extensions::StrEnum

Now you can use

User.str_enums

to list all columns has attached with str enum.

Make sure you have add lib directory into load path.

Ninh Le
  • 1,291
  • 7
  • 13
  • 1
    The method signature can be shortened to `def str_enum(column,*)` and the `super` call can just be `super`, since you only need `column` and all other arguments are a straight pass through – engineersmnky Dec 21 '20 at 20:12
1

So for starters, you could, of course, use the approach that Ninh Le has described and monkeypatch your desired behavior into the gem. In fact, I'm fairly confident that it would work, since your use case is currently relatively easy and you really just need to keep track of all the times the str_enum method gets called.

I would, however, encourage you to consider doing one of two things:

  • If you plan to do more complex stuff with your enums, consider using one of the more heavy-duty enum gems like enumerize, enumerate_it or active_enum. All of these are packages that have been around for a decade (give or take) and still receive support and all of them have been built with a certain degree of extensibility and introspection in mind (albeit with different approaches).
  • Have a look at the gem and consider building your own little macro on top of it. IMO one of multiple of Andrew Kane's libraries' biggest weaknesses is arguably their kind of hacky/scripty approach which, while making the libraries hard to extend, makes them inherently easy to understand and thus use as a basis for your own stuff (whereas the gems with a better/more elaborate approach are harder to understand and adapt beyond the means the author has intended to).

Either way, you'll be fine with both of my suggestions as well as Ninh Le's.

vgoff
  • 10,980
  • 3
  • 38
  • 56
Clemens Kofler
  • 1,878
  • 7
  • 11
  • Hi Clemens thank you for your answer. I quite like str_enum as it is lightweight and most importantly it stores the value as text in the database. – port5432 Dec 22 '20 at 07:03