В приложении электронной коммерции, которое я сейчас создаю, есть URL для удаления позиции в корзине пользователя:
http://127.0.0.1:3000/cart/line-item/16/destroy
Как и все хорошие обезьяны веб-кодирования, мне нужно проверить, что LineItem с идентификатором 16 действительно принадлежит пользователю, прежде чем уничтожать его. Звучит очевидно? Хорошо, что есть много веб-приложений, которые я видел, которые не выполняют эту проверку, часто просто предполагая, что идентификаторы базы данных, переданные через GET или POST, действительны.
Первоначальный способ кодирования действия destroy
LineItemsController
может быть:
def destroy fetch_order_from_session # sets up the @order object @line_item = LineItem.find(params[:id]) if @order.line_items.include?(@line_item) @line_item.destroy end end
другой способ может быть:
def destroy fetch_order_from_session @line_item = LineItem.find(:first, :conditions => ['id = ? AND order_id = ?', params[:id], @order.id]) @line_item.destroy end
Они оба работают, но не совсем красивые. Одна из предпосылок ассоциаций ActiveRecord заключается в том, что если вы определили связь между двумя объектами модели, вам не нужно повторяться, кодируя поиск по внешнему ключу вручную.
Менее известный (и плохо документированный) прием заключается в использовании метода find
ассоциации:
def destroy fetch_order_from_session @line_item = @order.line_items.find(params[:id]) @line_item.destroy end
Метод find
ассоциации работает точно так же, как обычный поиск, но выбор SQL автоматически ограничивается внешним ключом родителя. В этом случае в "order_id = #{@order.id}"
SQL SELECT добавляется "order_id = #{@order.id}"
. Вам не нужно останавливаться на простых находках, вы можете выполнять все свои обычные хитрости при поиске:
@order.line_items.find(:all, :conditions => ["quantity >= ?", 0])
Этот метод также полезен, если у вас есть объект пользователя, созданный before_filter
. Вместо того, чтобы добавлять user_id = @current_user.id
к каждой находке, просто выполните поиск непосредственно через ассоциацию объекта @current_user
. Если вы новичок в использовании ассоциаций, я предлагаю почитать предыдущую мою запись в блоге: злоупотребление ошибкой .. Использование AR :: Associations .
Как примечание, не забудьте убедиться, что это POST-запрос, используя макрос проверки ActionController . Вы бы не хотели, чтобы эти безумные голуби GET
испортили вашу прекрасную базу данных, не так ли?