RoR - Не уничтожайте объект, просто флаг как скрытый

У меня простая модель в RoR, и я бы хотел, чтобы все участники eveything вошли на сайт. Но я также хочу иметь возможность скрывать некоторый контент, если пользователь нажимает "Удалить".

Итак, я добавил атрибут bolean в моей модели под названием "отображается".

Я хотел бы знать, каков был бы метод, основанный на лучших методах.

Думаю, мне нужно сменить контроллер с чем-то вроде:

def destroy
 @point = Point.find(params[:id])
 @point.displayed = false
 @point.save

respond_to do |format|
  format.html { redirect_to points_url }
  format.json { head :no_content }
end

Но я не уверен, что он чист. Каким будет лучший способ сделать это.

Как вы думаете, я новичок с RoR. Куски кода будут оценены.

Спасибо

Ответ 1

Что-то вроде этого:

class Point < ActiveRecord::Base

  def archive        
    update_attribute!(:displayed, false)
  end 

end

И затем вызовите @point.archive в действие уничтожения вашего контроллера, где обычно вызывается @point.destroy. Вы также можете создать default_scope, чтобы спрятать заархивированные точки, пока вы явно не запросите их, найдите руководство RoR на используя область по умолчанию.

Изменить: обновил мой ответ в соответствии с нормальностью и комментариями логана ниже.

Ответ 2

Реализуйте его самостоятельно (вместо использования драгоценного камня). Это намного, намного проще, чем кажется на первый взгляд, и это менее сложно, чем любой из драгоценных камней, что изменить значение метода destroy, что является плохой идеей, на мой взгляд.

Я не говорю, что использование самих драгоценных камней сложное - я говорю, что, изменяя значение метода destroy, вы меняете смысл чего-то, что люди в мире Rails принимают как должное, - что когда вы вызываете destroy, эта запись будет уходить и что destroy может также быть вызвана на зависимые объекты, если они связаны друг с другом через обратные вызовы dependent: destroy.

Изменение значения destroy также плохо, потому что в мире "соглашение над конфигурацией", когда вы вставляете условные обозначения, вы по существу нарушаете "автоматичность" вашего кода Rails. Все, что вы считаете само собой разумеющимся, потому что вы читаете фрагмент кода Rails, и вы знаете, что некоторые предположения обычно применяются - они выходят из окна. Если вы измените эти предположения способами, которые не очевидны, вы почти наверняка представите ошибку из-за этой строки.

Не поймите меня неправильно, нет ничего лучше, чем на самом деле читать код для проверки ваших предположений, но также хорошо, как сообщество, чтобы иметь возможность говорить о некоторых вещах и, как правило, их поведение действует определенным образом.

Рассмотрим следующее:

  • В Rails ничего не говорится о том, что вы должны реализовать действие destroy в контроллере, так что нет. Это одно из стандартных действий, но это не требуется.
  • Используйте действие update, чтобы установить и очистить атрибут archived boolean (или что-то подобное)
  • Я использовал драгоценный камень acts_as_paranoid, и если вам нужно добавить какие-либо области к вашим моделям (кроме тех, которые предоставляет драгоценный камень), вам придется столкнуться с этим, выключив по умолчанию "скрыть архивные записи", и когда вы сталкиваетесь с этим, он почти сразу теряет свое значение. Кроме того, этот драгоценный камень практически ничего не делает сам по себе, и его функциональность может быть легко написана сама собой (и я имею в виду едва ли больше работы, чем сама установка самого драгоценного камня), поэтому на самом деле нет никакой пользы от ее использования с этой точки зрения.
  • Как было сказано ранее, переопределение метода или действия destroy является плохой идеей, поскольку это нарушает соглашение Rails (и ActiveRecord) относительно того, что означает вызов destroy для объекта. Любой драгоценный камень, который делает это (acts_as_paranoid, например), также нарушает это соглашение, и вы собираетесь запутать себя или кого-то другого, потому что destroy просто не будет означать, что он должен означать. Это добавляет путаницу, а не ясность в ваш код. Не делайте этого - вы заплатите за это позже.
  • Если вы хотите использовать жемчужину soft-delete, потому что вы защищаете от какого-то теоретического будущего разработчика, который может закрепить ваши данные... ну, лучшим решением для этого является не нанять или работать с этими людьми. Люди, которые неопытные нуждаются в наставничестве, а не драгоценный камень, чтобы помешать им совершать ошибки.
  • Если вы действительно абсолютно должны предотвратить уничтожение записи данной модели (в дополнение к возможности просто ее архивировать), используйте обратный вызов before_destroy и просто верните false, что предотвратит его уничтожение на все, если не используется явный вызов delete (что в любом случае не то же самое, что уничтожать). Кроме того, наличие обратного вызова делает его (а) действительно очевидным, почему destroy не работает без изменения его значения, и (б) легко написать тест, чтобы убедиться, что он не может быть уничтожен. Это означает, что в будущем, если вы случайно удалите этот обратный вызов или сделаете что-то еще, что сделает эту модель разрушаемой, тогда тест не удастся, предупредив вас об этой ситуации.

Ответ 3

Посмотрите на acts_as_archive gem. Он будет мягко удалять файлы.

Ответ 4

Ваше решение хорошо, но вы можете использовать act_as_paranoid gem для управления этим.

Ответ 5

В этом сценарии вместо добавления нового логического флага лучше добавить deleted_at:datetime

@point = Point.find(params[:id])
@point.touch(:deleted_at)
...

Тогда позже

Point.where(deleted_at: nil) # these are NOT hidden
Point.where.not(deleted_at: nil) # these are hidden