Как установить доступ только для чтения в модели рельсов, используя атрибут внутри модели?

Как сделать модель доступной только для чтения каждый раз, когда к ней обращаются, если для атрибута в той же модели установлено значение true?

Я искал везде, и модель только для чтения, похоже, имеет очень мало документации и даже веб-результатов.

Изменить (дополнительная информация): у меня есть два метода в моей модели (application.rb) - не в частном порядке

  def lock()
    self.locked = true
    save(validate: false)
  end

  def unlock()
    self.locked = false
    save(validate: false)
  end

Я вызываю их из моего контроллера приложений при обновлении с помощью:

if params[:application][:locked] == false
  @application.unlock
  return
elsif params[:application][:locked] == true
  @application.lock
  return
end

а в Модели (application.rb) у меня - не в привате:

  def readonly?
    locked == true
  end

person notADevAccount    schedule 26.11.2018    source источник
comment
Это дубликат stackoverflow.com/questions/53432372/ Не так ли?   -  person iGian    schedule 26.11.2018
comment
@iGian - это несколько дубликат. Я сделал это, потому что чувствовал, что эта тема немного отличается от темы моего основного вопроса в этом посте, поэтому я хотел убедиться, что они существуют отдельно, чтобы можно было ответить на оба вопроса отдельно (и, надеюсь, помочь кому-то еще с этими вопросами). Речь идет о том, чтобы сделать модель доступной только для чтения на основе атрибутов внутри модели, а другая — о разрешении только определенных атрибутов только для чтения.   -  person notADevAccount    schedule 26.11.2018
comment
@notADevAccount Когда вы говорите, что модель rails доступна только для чтения, вы намеревались установить доступ только для чтения ко всей модели (всем записям)? или установить доступ только для чтения для экземпляра этой модели (динамически разрешенный для каждого экземпляра)?   -  person Jay-Ar Polidario    schedule 26.11.2018
comment
@ Jay-ArPolidario - Да, мне нужно установить его по экземпляру, потому что каждая запись будет иметь атрибут с именем «заблокировано», который должен определять, доступна ли эта конкретная запись только для чтения. если true, то он доступен только для чтения и не должен разрешать запись.   -  person notADevAccount    schedule 26.11.2018
comment
@notADevAccount Понятно, тогда я думаю, что мой ответ — это то, что вы искали? :)   -  person Jay-Ar Polidario    schedule 26.11.2018
comment
@Jay-ArPolidario - Да, я так думаю, но у меня есть вопрос: когда я помещаю метод def readonly? в свою модель (общедоступную), у меня есть locked == true в качестве условия, но, похоже, модель доступна только для чтения независимо от атрибута.   -  person notADevAccount    schedule 26.11.2018
comment
@notADevAccount Если это тот же код, что и ваши stackoverflow.com/questions/53432372/ где находится этот набор locked (например, где оценивается значение true или false из)? Кроме того, не могли бы вы обновить свой вопрос, включив в него этот конкретный код locked? просто чтобы другим пользователям SO не нужно было переходить к вашему другому вопросу.   -  person Jay-Ar Polidario    schedule 26.11.2018
comment
@notADevAccount Является ли locked атрибутом вашей модели? Если это так, то ваш if locked; def readonly?; true; end; end неверен, потому что снаружи def readonly? ... end, self == Model, а не self экземпляр Model. Я расскажу об этом подробнее после того, как вы сначала подтвердите, верны ли мои предположения/догадки.   -  person Jay-Ar Polidario    schedule 26.11.2018
comment
@Jay-ArPolidario - я обновил вопрос своим кодом   -  person notADevAccount    schedule 26.11.2018
comment
@notADevAccount Я обновил свой ответ, дайте мне знать, если вы намеревались это сделать   -  person Jay-Ar Polidario    schedule 26.11.2018


Ответы (1)


Обновлено:

# app/models/application.rb

# I highly suggest renaming `Application` into something else because, Rails
# already has a same defined constant name `Application` which is defined in your
# app/config/application.rb

class Application < ApplicationRecord
  def lock!
    # depending on your use-case I'll do an `update` below instead
    # self.lock = true
    update!(locked: true)
  end

  def unlock!
    # self.lock = false
    update!(locked: false)
  end
end

# app/models/user.rb
class User < ApplicationRecord
  belongs_to :application

  def readonly?
    # this is still subject to race-condition even though already `reloaded`
    application.reload.locked || some_user_attribute == 'HELLO WORLD!'
  end
end

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

  def readonly?
    # this is still subject to race-condition even though already `reloaded`
    application.reload.locked || some_comment_attribute_like_is_disabled?
  end
end

Обратите внимание, что я добавил сюда ассоциацию belongs_to, потому что она вам, скорее всего, понадобится, потому что ваша Application, как вы сказали, на самом деле уже является обычной моделью. Если у вас нет этой ассоциации и вы устанавливаете locked внутри себя как переменную экземпляра класса вашего класса Application (т. е. у вас есть переменная экземпляра класса @locked), то (в зависимости от ваших требований) у вас возникнут проблемы с 1) постоянством потому что каждый запрос (для разных процессов/серверов) по умолчанию будет иметь значение locked = nil (что может быть проблемой для вас, а может и не быть), а также 2) параллелизм, поскольку потоки совместно используют значение этой переменной экземпляра класса, что означает, что одновременные запросы потребуются это значение @locked оценивается независимо; что становится потенциально опасным, если @locked установлено в true в одном потоке, а в другом @locked переопределено и установлено в false. Но если это не проблема, я все равно могу обновить свой ответ, чтобы не использовать belongs_to :application; дайте мне знать.

person Jay-Ar Polidario    schedule 26.11.2018
comment
Поэтому мне все еще трудно понять, что это значит. Заставляет ли установка только для чтения пользователя проверять, доступно ли приложение только для чтения для каждого экземпляра? Моя модель приложения: class Application < ApplicationRecord - person notADevAccount; 26.11.2018
comment
@notADevAccount ооо, я вижу, когда вы сказали application.rb, я подумал, что вы имеете в виду класс с условным названием app/config/application.rb. Независимо от того, какой класс вы устанавливаете self.locked = true or false, для обеспечения потокобезопасности вам все равно понадобится что-то вроде Thread.current. - person Jay-Ar Polidario; 26.11.2018
comment
@notADevAccount Однако, чтобы ответить на ваш вопрос, да, def readonly? - это метод instance, потому что вместо этого метод class будет похож на def self.readonly?. Поскольку это метод instance, тогда да, этот метод оценивается для каждого экземпляра Модели (что, как и ожидалось, от того, как Rails правильно реализовал этот метод def readonly), и я проверил, что этот метод вызывается/вызывается всякий раз, когда экземпляр этой Модели имеет создано/обновлено/уничтожено. - person Jay-Ar Polidario; 26.11.2018
comment
@notADevAccount Сейчас я обновляю свой код, чтобы отразить неправильный код application.rb, который я предполагал - person Jay-Ar Polidario; 26.11.2018
comment
@notADevAccount о, теперь я понимаю, Application на самом деле нормальная модель, а не абстрактный подкласс ApplicationRecord? и что у него есть атрибут под названием locked? Тогда да, я не думаю, что вам нужно беспокоиться о потокобезопасности. Я обновил свой ответ. - person Jay-Ar Polidario; 26.11.2018
comment
Хорошо, это имеет больше смысла! Большое спасибо! Я отметил как ответ... Я тоже проголосовал, но, очевидно, это не будет показано публично из-за моей низкой репутации. Я ценю всю вашу помощь! - person notADevAccount; 26.11.2018
comment
@notADevAccount не беспокойтесь! Рад помочь :) - person Jay-Ar Polidario; 26.11.2018