Best way to store Enum value in ActiveRecord and convert to string for display

前端 未结 5 1776
野的像风
野的像风 2021-02-02 17:05

I am trying to figure out what is the best way to store an enum value in activerecord but convert it to a \'title\' for display in an app.

I.E.

Review Enum:

相关标签:
5条回答
  • 2021-02-02 17:32

    ActiveRecord enums is the best way to go since it's a part of the framework (since version 4.1).

    Its usage is quite simple:

    Migration:

    class AddEnumToMyModel < ActiveRecord::Migration
      def change
        add_column :my_model, :status, :integer, default: 0
      end
    end
    

    Model:

    class MyModel < ActiveRecord::Base
      enum status: [:draft, :beta, :public]
    end
    

    Then use it a will:

    MyModel.draft # gets all drafts
    MyModel.last.draft? # checks if the last model is draft
    MyModel.last.status # gets the string description of the status of my model
    

    For mode information refer to documentation.

    0 讨论(0)
  • 2021-02-02 17:43

    there are a lot of posts about this issue, i guess that this points to most of them: http://thinkinginrails.com/2010/04/using-enums-for-constants/

    i think that this is an over engineered thing, that you don't need in a dynamically typed language like ruby.

    just use strings!

    you could then use that like:

    class Review < ActiveRecord::Base
      validates_inclusion_of :status, :in => ["UNREVIEWED", "REVIEWED", "FLAGGED"]
      def status
        read_attribute(:status)
      end
      def status= (value)
        write_attribute(:status, value)
      end
    end
    
    0 讨论(0)
  • 2021-02-02 17:43

    While I agree that @Godsaur answer is correct - I personally don't like the approach of storing integer values to represent meaningful string equivalents (provided that enough database indexing is made and/or the cost of querying strings in the DB engine is similar to that of querying integers).

    My approach is usually storing the text values in the database (for easier understanding of DB records).

    my_model.rb

    class MyModel < ActiveRecord::Base
    
      STATUSES = HashWithIndifferentAccess.new({unverified: 'unverified', reviewed: 'reviewed', flagged: 'flagged'})
      #the text values are similar to their symbols key
      #you could also define additional attributes for each key if needed. Ex:
      #STATUSES = {unverified: {title: 'Unverified Text Title', txt: 'unverified'}, ...}
    
      # assuming a 'status' field
      scope :unverified, -> { where(status: STATUSES[:unverified]) }
    
      def unverified?
        status == STATUSES[:unverified]
      end
    
      # Or
      STATUSES.each do |sym, val|
        define_method("#{sym}?") {status == val}
      end
    end
    

    my_view.erb

    <%= MyModel::STATUSES[@my_model.status] %> or 
    <%= MyModel::STATUSES[@my_model.status].title %>
    
    0 讨论(0)
  • 2021-02-02 17:49

    Using @Godsaur example.

    class MyModel < ActiveRecord::Base
      enum status: [:draft, :beta, :public]
    end 
    

    You can get the string value as:

    MyModel.last.status
    => "beta"
    

    But if you want a "title" you can:

    MyModel.last.status.titleize
    => "Beta"
    
    0 讨论(0)
  • 2021-02-02 17:54

    I agree with @tamersalama. Here's a simple way to do it using strings in the DB with a custom Enum class. Note that this also supports human readable names for use in dropdown menus.

    https://gist.github.com/alexch/a7be54e1b085718473ff

    SQL:

    Table name: snacks
     id                         :integer
     ice_cream                  :string
    

    Rails:

    class Snack < ActiveRecord::Base
      FLAVORS = Enum.new [
          [:vanilla, "Vanilla"],
          [:chocolate, "Chocolate"],
          [:rocky_road, "Rocky Road"]
          ])
      ]
    end
    

    HTML:

    <%= simple_form_for @snack do |f| %>
    <%= f.collection_select :ice_cream, Snack::FLAVORS, :value, :label %>
    <% end %>
    
    0 讨论(0)
提交回复
热议问题