Поиск продуктов на основе критериев


Метод должен искать продукты нашли по заданным критериям и сохранять их в @изделий.

Критерии таковы:

  • Если пользователь вводит что-то в text_field (:search_keywords) тогда имя продукта должен быть согласован с этим словом
  • Если пользователь указывает product_type (:продукт[:тип]) все найденные товары должны быть этого типа.

def search
  if params[:search_keywords] && params[:search_keywords] != ""
    @products = Product.where("name LIKE '%" + params[:search_keywords] + "%'")
    if params[:product] && params[:product][:type] && params[:product][:type] != ""
      @products = Product.where("name LIKE '%" + params[:search_keywords] + "%' AND product_type_id = " + params[:product][:type])
    end
  else
    if params[:product] && params[:product][:type] && params[:product][:type] != ""
      @products = Product.find_all_by_product_type_id(params[:product][:type])
    else
      @products = Product.all
    end
  end
end


Комментарии
5 ответов

Попробуйте использовать области, его намного приятнее

def search
@products = Products.scoped
if !params[:search_keywords].blank?
@products = @products.where("name LIKE ?", "%#{params[:search_keywords]}%")
end
if !params[:product].try(:[], :type).blank?
@products = @products.where(:product_type_id => params[:product][:type])
end
@products # maybe @products.all if realy needed
end

8
ответ дан 3 июня 2011 в 02:06 Источник Поделиться

Я видел коды многих Railers' искушать впихнуть много логики в представлении и контроллере. Позвольте мне добавить эти важные акценты:


  1. Тощий контроллер толстая модель , которая является одной из самых элегантных рельсы пути принципов.

  2. И Испытания.

Вот у меня products_controller.РБ файл в приложение/контроллеры каталог, который содержит это:

class ProductsController < ApplicationController
def search
@products = Product.search(params)
end
end

Я ставлю логику в модели. Вот мой продукт.РБ файл в приложение/модели каталога:

class Product < ActiveRecord::Base
scope :nm, lambda { |n| where "name LIKE ?", '%' + n + '%' }
scope :criteria, lambda { |n, type| nm(n).where type_id: type }

def self.search(opts={})
return all if opts.empty?
return nm(opts[:search_keywords]) unless opts[:search_keywords].nil?
return criteria(opts[:name], opts[:type]) if opts[:product].try(:[], :type).empty?
end
end

Также можно попробовать поэкспериментировать динамический объем работ по улучшению продукта код модели выше. Я не пробовал это успешно и эффективно здесь, дайте мне знать, если кто может сделать это лучше, в любом случае.

И Испытания. Вы также можете проверить свои приложения с помощью тестирования RSpec, огурец, рубиновый селен, Watir, или любой другой тест для Ruby, но здесь я только покажу вам, как сделать это с помощью Ruby unit-тестирования. Вот мой product_test.РБ внутри тест/блок каталога:

require 'test_helper'
require 'product'

class ProductTest < ActiveSupport::TestCase
fixtures :products

def test_nm
assert_equal Product.nm("Pick").first.name, products(:pickaxe).name
end

def test_criteria
assert_equal Product.criteria("Bach", 2).first.name, products(:bach).name
end

def test_search
assert_equal Product.search(:search_keywords => "Pick").first.name,
products(:pickaxe).name
assert_equal Product.search(:search_keywords => "Pick", :type => 1).first.name,
products(:pickaxe).name
assert_equal Product.search.size, Product.count
end
end

И связанных с приспособление. Вот мои продукты.YML в файл внутри теста/приспособления каталога:

pickaxe:
name: Pickaxe 3
type_id: 1

bach:
name: Bach
type_id: 2

lotr:
name: LOTR
type_id: 3

И для тестирования контроллера, вот мой products_controller_test.РБ файл внутри испытания/функциональный каталог:

require 'test_helper'
require "products_controller"

class ProductsControllerTest < ActionController::TestCase
fixtures :products

test "should get search" do
get :search, :search_keywords => 'Pick', :product => { :type => '1' }
assert_response :success
assert_not_nil assigns(:products)
end
end

Давайте проверим их. Я использую:

. ruby -v
ruby 1.9.2p0 (2010-08-18) [i386-darwin9.8.0]
. rails -v
Rails 3.0.9

Вот результат моего теста:

. rake test
(in /Users/arie/se/tester)
NOTICE: CREATE TABLE will create implicit sequence "products_id_seq" for serial column "products.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "products_pkey" for table "products"
Loaded suite /opt/experiment/ruby/lib/ruby/1.9.1/rake/rake_test_loader
Started
...
Finished in 0.237899 seconds.

3 tests, 5 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 54809
Loaded suite /opt/experiment/ruby/lib/ruby/1.9.1/rake/rake_test_loader
Started
.
Finished in 0.330431 seconds.

1 tests, 2 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 25681

Хорошо! Работал как шарм! 0 ошибок за оба блока (для модели) и функциональной (для контроллера) тесты. Я также проверил это с моим браузером, и он работал.

Можно также скачать мою копию файлов здесь.

Ссылки:


  1. Тестирование Ссылка

  2. Начиная с огурца RailsCasts

  3. Активная Запись Запроса Интерфейсом 3.0

  4. Skinny на области (ранее named_scope)

6
ответ дан 23 июня 2011 в 03:06 Источник Поделиться


  1. Вы можете использовать пустые?

  2. Вам нужны пользовательские параметры в SQL-запросе.

  3. Возможно, вам нужно Escape-символа % в search_keywords.

def search
keywords_blank = params[:search_keywords].blank?
type_blank = params[:product] && !params[:product][:type].blank?

@products = if keywords_blank && type_blank
Product.all
elsif keywords_blank
Product.find_all_by_product_type_id(params[:product][:type])
elsif type_blank
Product.find(:all, :conditions => ["name LIKE :name", :name => "%#{params[:search_keywords]}%"])
else
Product.find(:conditions => ["name LIKE :name AND product_type_id = :type", {:name => "%#{params[:search_keywords]}%", :type => params[:product][:type]}])
end
end

1
ответ дан 31 мая 2011 в 09:05 Источник Поделиться

Вы можете использовать комбинацию из областей, чтобы упростить код. Также, вы можете воспользоваться удобной Руби/ActiveSupport методов и конвенций, чтобы избежать если условия.

def search
@products = Product.scoped
@products = @products.search_by_name(params[:search_keywords])
@products = @products.search_by_type(params[:product][:type] rescue nil)
# in your view
# @products.all
end

class Product

def self.search_by_name(value)
if value.present?
where("name LIKE ?", "%#{value}%")
else
self
end
end

def self.search_by_type(value)
if value.present?
where(:product_type_id => value)
else
self
end
end

end

0
ответ дан 28 августа 2011 в 08:08 Источник Поделиться

Мне нравится Goethals Берт, ответы Арье и Симоне Карлетти это - мое решение будет касаться каждого:

в ваш контроллер:

class ProductsController < ApplicationController

def search
keywords = params[:search_keywords]
type_id = params[:product].try(:[],:type)
@products = Product.search({:type_id => type_id, :keywords => keywords})
end

end

в вашей модели

  def self.search(options={})
keywords = options[:keywords]
type_id = options[:type_id]

products = Product.scoped
products = products.where("name like ?","%#{keywords}%") if keywords.present?
products = products.where(:type_id => type_id) if type_id.present?
products
end

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

0
ответ дан 10 июня 2012 в 06:06 Источник Поделиться