Построение Rails ActiveRecord где предложение - PullRequest
16 голосов
/ 28 апреля 2011

Каков наилучший способ создания предложения where с использованием Rails ActiveRecord? Например, допустим, у меня есть действие контроллера, которое возвращает список сообщений в блоге:

def index
  @posts = Post.all
end

Теперь, допустим, я хочу передать параметр url, чтобы это действие контроллера возвращало сообщения только определенного автора:

def index
  author_id = params[:author_id]

  if author_id.nil?
    @posts = Post.all
  else
    @posts = Post.where("author = ?", author_id)
  end
end

Мне это не очень СУХО. Если бы я добавил порядок или нумерацию страниц или, что еще хуже, дополнительные необязательные параметры строки URL-запроса для фильтрации, это действие контроллера стало бы очень сложным.

Ответы [ 5 ]

24 голосов
/ 28 апреля 2011

Как насчет:

def index
  author_id = params[:author_id]

  @posts = Post.scoped

  @post = @post.where(:author_id => author_id) if author_id.present?

  @post = @post.where(:some_other_condition => some_other_value) if some_other_value.present?
end

Post.scoped - это, по сути, ленивый загруженный эквивалент Post.all (поскольку Post.all возвращает массив немедленно, в то время как Post.scoped просто возвращает объект отношения). Этот запрос не будет выполнен до вы на самом деле пытаетесь перебрать его в представлении (вызывая .each).

2 голосов
/ 28 апреля 2011

Ммм, лучший подход, который вы хотите использовать, - это распространить его в 2 действия

def index
   @post = Post.all
end

def get
  @post = Post.where("author=?", params[:author_id])
end

ИМХО, имеет больше смысла, если вы думаете о RESTful API, индекс означает перечислять все и получать (или показывать), чтобы получить запрошенный и показать его!

0 голосов
/ 15 февраля 2019

Этот вопрос довольно старый, но он все еще высоко ценится в Google в 2019 году, а также некоторые более ранние ответы устарели, поэтому я подумал, что поделюсь возможным решением.

В модель введены некоторые области с проверкой на наличие переданного параметра:

class Post
    scope :where_author_ids, ->(ids){ where(author_id: ids.split(‘,’)) if ids }
    scope :where_topic_ids,  ->(ids){ where(topic_id:  ids.split(‘,’)) if ids }

Затем в контроллере вы можете установить столько фильтров, сколько пожелаете, например:

def list
    @posts = Post.where_author_ids(params[:author_ids])
                 .where_topic_ids(params[:topic_ids])                                  
                 .where_other_condition_ids(params[:other_condition_ids])
                 .order(:created_at)

Параметр может быть одним значением или списком значений, разделенных запятыми, оба работают нормально.

Если param не существует, он просто пропускает условие where и не фильтрует для этого конкретного критерия. Если параметр существует, но его значение является пустой строкой, он будет «отфильтровывать» все.

Это решение, конечно, не подойдет для любых обстоятельств. Если у вас есть страница просмотра с несколькими фильтрами, но при первом открытии вы хотите показать все свои данные, а не данные, пока не нажмете кнопку «Отправить» или аналогичную (как это сделал бы контроллер), вам придется слегка подправить ее. ,

Я попробовал SQL-инъекцию, и rails, кажется, отлично справляется с обеспечением безопасности всего, насколько я вижу.

0 голосов
/ 28 апреля 2011

Вы должны смоделировать URL, используя вложенные ресурсы. Ожидаемый URL будет / авторы / 1 / сообщений. Думайте об авторах как о ресурсах. Подробнее о вложенных ресурсах читайте в этом руководстве: http://guides.rubyonrails.org/routing.html (выделите 2.7 - Вложенные ресурсы).

0 голосов
/ 28 апреля 2011

Хотелось бы что-нибудь подобное?

def get
  raise "Bad parameters...why are you doing this?" unless params[:filter].is_a?(Hash)
  @post = Post.where(params[:filter])
end

Тогда вы можете сделать что-то вроде:? Filter [author_id] = 1 & filter [post_date] = ... etc.

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