Статьи

Использование AR :: Associations для ограничения области поиска ()

В приложении электронной коммерции, которое я сейчас создаю, есть 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 испортили вашу прекрасную базу данных, не так ли?