Ruby - Ensure only one class object

断了今生、忘了曾经 提交于 2019-12-11 16:18:37

问题


I have a Model Bot and I would like to ensure that there is only one Bot object in my database. I also need to make sure it is persisted and not tampered with.

My original thought was to do this in a migration, one that would follow the :bots table migration. It would include a line that is something like:

Bot.all.size == 0 ? Bot.create! : nil

Maybe this would prevent the AR object from being messed with in future migrations?


BONUS: Would be awesome to be able to have instant and global access to this class object. I was thinking using a singleton module in my Bot class that way I can always reference Bot.instance and have access to that specific object.


USE CASE:

I have 4 types of users in my DB and this bot will be the facilitator to delivery role-specific messages to them through our in-app messaging feature.

The Class Bot will have a has_many association with BotMessage/bot_messages. On the bot_messages table will be an enum field for user_role.

Messages will be created by company admins and stored in these tables because we want them to be viewable at any time by looking at the "conversation" thread between the User and the Bot.

When it comes to only having 1 bot, it's just that. I have no need for an additional Bot object. Additionally, since there is only one object it would be nice to be able to have a way of explicitly targeting that object without having to run a query to find it.

For example, unlike User where there could be 1000 records and in order to find the specific one you would do something like @user = User.find_by_email('foo@bar.com'), doing something like that for the bot would be unnecessary since there is only one record to find. That is what lead me to believe having a singleton object may be worthwhile here, so whenever I need to pull up a message for a specific role, I could run Bot.instance.bot_messages.where(user_role: 1) or something similar


回答1:


Based on your Use Case, I see no reason for Bot to be a model.

Let's say you have a role called cool_user and you want to get all the bot_messages for that role, you might do something like:

class Bot

  class << self

    def bot_messages(user_role)
      BotMessage.send(user_role)
    end

  end

end

As a very thoughtful but potentially anonymous super code monkey notes in the comments, you could also do:

class Bot

  def self.bot_messages(user_role)
    BotMessage.send(user_role)
  end

end

Which some folks might find more readable. IMO, it is a bit of an issue of personal preference.

In either case, you should be able to do

Bot.bot_messages(:cool_user)

Since, as stated in the docs,

Scopes based on the allowed values of the enum field will be provided as well.

So, I believe BotMessage, with the properly set enum, should respond to cool_user and return all the bot_messages for that role.

You may need to check the docs to get the syntax exactly right.

I believe this should also satisfy your BONUS requirement.




回答2:


A proven solution would be to use an STI on User (with a user_type column)

class User < ApplicationRecord
  ...
end

class Bot < User
  has_many :bot_messages, foreign_key: :user_id
end

Is it what you're looking for ?



来源:https://stackoverflow.com/questions/49074848/ruby-ensure-only-one-class-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!