#ruby-on-rails
#ruby-on-rails
Вопрос:
Используя ROR 2.3.8.
Вот мой код:
class CitiesController < ApplicationController
def show
...
end
def western
@city = City.find(params[:id])
@spots = Spot.paginate(
:conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Places"],
:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
def middle-east
@city = City.find(params[:id])
@spots = Spot.paginate(
:conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Food"],
:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
def asian
@city = City.find(params[:id])
@spots = Spot.paginate(
:conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Accommodation"],
:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
end
Я создал western.html.erb
, middle-east.html.erb
asian.html.erb
и _shops.html.erb
.
Итак, первые три в основном пустые, но выдают _shops.html.erb
, чтобы мне не приходилось перекодировать макет представления.
Есть ли лучший метод при написании контроллера?
Спасибо!
Комментарии:
Ответ №1:
Правильный способ высушить это в Rails 2.3.X — это именованная область в вашей модели. Чрезмерные / повторяющиеся запросы в вашем контроллере — это намек на запах кода. Если вы мне не верите, то Джеймис Бак прикроет мою спину! http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model
В вашей точечной модели:
# app/models/spot.rb
named_scope :by_type, lambda { |city, type|
{:conditions => ["(city=? or state=?) and country=? and shop_type=?", city.name, city.name, city.country, type] }
}
В вашем контроллере Cities:
#app/contollers/cities_controller.rb
before_filter :fetch_city, :except => :show
def western
@spots = paginate_spots("Places")
end
....
private
def fetch_city
@city = City.find(params[:id])
end
def paginate_spots(type)
Spot.by_type(@city,type).paginate(:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
Чего это достигает, так это удаления большей части логики запросов из контроллера. Это хорошая вещь, поскольку позволяет находить точки по городу и вводить другие контроллеры, если возникнет необходимость. Разбивка на страницы, вероятно, зависит от вашего отдельного контроллера, поэтому я склонен исключать его из областей внутри моделей. Если вы хотите создать API, вы можете ограничить его 50 вместо 20, например, и хотите выполнить сортировку другим методом.
Комментарии:
1. Спасибо. Я получил эту ошибку
Mysql::Error: Operand should contain 1 column(s): SELECT * FROM
spots` ГДЕ (spot_type=1,’Accommodation’) ПОРЯДОК ПО rating_average ОГРАНИЧИВАЕТ ЗНАЧЕНИЕ 0, 20`, которое, я думаю,spot_type
должно быть равно"Accommodation"
. Как мне это исправить? Также{}
необходим from:conditions ... , type]
.2. Мой плохой, у меня есть два
:by_type
с именем named_scope. Переименовали его во что-то другое, и это работает безупречно. Спасибо!3. Я исправил проблему synax, на которую вы указали в своем комментарии. Мне действительно сложно отлаживать инструкцию, не имея полной информации о моделях. Единственное, что вы можете попробовать, это разделить области на более мелкие и увидеть желаемые результаты. Вы можете объединить области вместе, такие как Spot.by_state_or_city (@city.name ).by_country(@city.country).by_type(«Размещение») во время отладки.
4. @Patrick Robertson, как указано выше, это моя вина, что я не знал, что уже существует другой
:by_type
named_scope. Теперь это работает. Спасибо!5. @Patrick Robertson, что, если я хочу показать все типы? Что я должен вставить для замены
Places
вpaginate_spots("Places")
, чтобы отобразить все типы?
Ответ №2:
Первый подход: используйте before_filter
. upd: у вас это не сработает (я оставлю это здесь в образовательных целях)
class CitiesController < ApplicationController
before_filter :spots_and_city, :only => [:asian, :western, :middle-east]
def show
...
end
def western
end
def middle-east
end
def asian
end
private
def spots_and_city(type)
@city = City.find(params[:id])
@spots = Spot.paginate(
:conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, "Accommodation"],
:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
end
Использование второго подхода helper method
: обновлено
class CitiesController < ApplicationController
helper_method :spots, :city
def show
...
end
def western
@city = city
@spots = spots("Places")
end
def middle-east
@city = city
@spots = spots("Food")
end
def asian
@city = city
@spots = spots("Accommodation")
end
private
def city
city ||= City.find(params[:id])
end
def spots(type)
spots ||= Spot.paginate(
:conditions => ["(city=? or state=?) and country=? and shop_type=?", "#{@city.name}", "#{@city.name}", @city.country, type],
:page => params[:page],
:per_page => 20,
:order => 'rating_average DESC'
)
end
end
Третье: использовать Decent Exposure
На мой взгляд, я предпочитаю использовать helper_method
для такой работы.
Комментарии:
1. Спасибо. Но в моем последнем значении для строки условия есть определенное
shop_type
для каждого. Вы не возражаете просмотреть свой код?2. Кстати, что
||
делает вcity ||= City.find(params[:id])
?3. Это кэширование. оформить заказ railscasts.com/episodes/1-caching-with-instance-variables
4. Спасибо. Последний вопрос: почему ты такой замечательный?
5. Пожалуйста, еще немного информации. Это не похоже на ошибку из-за helper_method