Ruby on Rails: проверьте количество товаров, которые есть в магазине - PullRequest
3 голосов
/ 12 октября 2010

Я возлюсь с проектом по тестированию / упражнениям, чтобы лучше понять Rails.

В моем случае у меня есть три модели: Магазин, Пользователь и Продукт.

Магазин может быть трех типов: базовый, средний, большой. Basic может иметь до 10 продуктов максимум, средний 50, большой 100.

Я пытаюсь проверить данные такого типа, тип магазина и проверить, сколько продуктов принадлежит ему при создании нового продукта.

Пока что я придумал этот код (в shop.rb), но он не работает:

  def lol
      account = Shop.find_by_sql "SELECT account FROM shops WHERE user_id = 4 LIMIT 1"
    products = Product.count_by_sql "SELECT COUNT(*) FROM products WHERE shop_id = 13"
    if account = 1 && products >= 10
        raise "message"
    elsif   account = 2 && products >= 50
        raise "message"
    else account = 3 && products >= 100
        raise "message"
    end
end

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

has_many

а его метод "размер"? Я не знаю. :)

Ответы [ 6 ]

6 голосов
/ 12 октября 2010

Как минимум измените account = 1 на account == 1.То же самое касается account = 2 и account = 3.

Кроме этого, я бы порекомендовал вам взглянуть на Rails Guides , чтобы получить представление об использовании Rails.

То естьсказал, я предлагаю что-то вроде этого:

class Shop < ActiveRecord::Base
  has_many :products
  validates :products_within_limit

  # Instead of the 'account' column, you could make a 'max_size' column.
  # Then you can simply do:
  def products_within_limit
    if products.size > max_size
      errors.add_to_base("Shop cannot own more products than its limit")
    end
  end

  def is_basic?
    products.size >= 10 && products.size < 50 
  end

  def is_medium?
    products.size >= 50 && products.size < 100
  end

  def is_big?
    products.size >= 100
  end

  def shop_size
    if self.is_basic?
      'basic'
    elsif self.is_medium?
      'medium'
    elsif self.is_big?
      'big'
    end
  end
end

Это позволяет вам сделать:

# Get shop with id = 1
shop = Shop.find(1)

# Suppose shop '1' has 18 products:
shop.is_big? # output false
shop.is_medium? # output false
shop.is_basic? # output true
shop.shop_size # output 'basic'
3 голосов
/ 13 октября 2010

это не должно быть так сложно:

class Shop < ActiveRecord::Base
  has_many :products

  validate :check_nr_of_products

  def check_nr_of_products
    nr_of_products = products.size
    errors[:base] << "Basic shops can have max 10 products" if account == 1 && nr_of_products > 10
    errors[:base] << "Medium shops can have max 50 products" if account == 2 && nr_of_products > 50
    errors[:base] << "Big shops can have max 100 products" if account == 3 && nr_of_products > 100
  end        

эта проверка проверяется каждый раз при сохранении. Вам не нужно извлекать «тип счета», предполагая, что это поле магазина. Аналогично, вместо написания запроса для подсчета количества продуктов, используйте функцию size, которая делает именно это.

Это простое решение. Решение STI, предложенное @Dave_Sims, является действительным и более объектно-ориентированным.

3 голосов
/ 12 октября 2010

Вот еще один возможный Rails-й способ достижения этого.Это мой собственный вкус - заставить Ruby имитировать поведение абстрактного класса (Shop).YMMV.

РЕДАКТИРОВАТЬ: обратите внимание, что я заменяю переменную «account» из примера OP на наследование, используя Inheritance Single Table Inheritance , который использует столбец «type» для выполнения в основном той же функциино используя наследование, чтобы выразить различные виды магазинов и их соответствующие лимиты продуктов. Исходный пример OP, вероятно, нарушает Принцип замещения Лискова , и STI - один из способов исправить это.

РЕДАКТИРОВАТЬ: Как будто я недостаточно педантичен, техническиНа самом деле это не нарушение Лискова, а Открытое / Закрытое нарушение .Они все вариации на одну тему.Вы поняли.

class Product < ActiveRecord::Base
  belongs_to :shop
end

class Shop < ActiveRecord::Base
  has_many :products  
  belongs_to :user
  validates :products_within_limit

  def products_within_limit
    if products.count > limit
      errors.add_to_base("Shop cannot own more products than its limit")
    end
  end

  def limit
    raise "limit must be overridden by a subclass of Shop."
  end
end

class BasicShop < Shop
  def limit
    10
  end
end

class MediumShop < Shop
  def limit
    50
  end
end

class LargeShop < Shop
  def limit
    100
  end
end

shop = BasicShop.create
10.times {Product.create(:shop => shop)}
shop.reload
shop.valid? # is true
shop.products << Product.new
shop.valid? # is false
1 голос
/ 12 октября 2010

Это должно вам помочь.

0 голосов
/ 15 октября 2010

Опять же, спасибо за огромную поддержку. Я закончил тем, что украл у вас решения и реализовал этот код:

#in shop.rb
validate :is_account                                                

def is_account
    if account == 1
        limit = 10
    elsif account == 2
        limit = 50
    else account == 3
        limit = 100
    end
    errors.add(:base, "Reached maximum number of items for shop") if account == account && products.size >= limit
end

#in products_controller.rb

def new
if current_user.shop.nil?
    flash[:alert] = I18n.t 'shops.create.must'
    redirect_to :action => :index
elsif current_user.shop.invalid?
    flash[:alert] = I18n.t 'shops.upgrade.must'
    redirect_to :action => :index
else
    @product = Product.new
  end
end

Кажется, до сих пор работает. Надеюсь, я не совершил вопиющей ошибки.

Еще раз спасибо! :)

0 голосов
/ 14 октября 2010

Ну, во-первых, спасибо всем за большую помощь и проницательную дискуссию. :)

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

То, что я сделал, было:

class Shop < ActiveRecord::Base

belongs_to :user
has_many :products, :dependent => :destroy
validate :is_account                                                

def is_account
    if account == 1 && products.size < 11
    elsif account == 2 && products.size < 51
    else account == 3 && products.size < 101
    end
end

Затем в products_controller.rb я помещаю эти строки:

def new
if current_user.shop.nil?
    flash[:notice] = I18n.t 'shops.create.must' #this should check is the user owns a shop, otherwise can't add a product. It seems to work, so far
    redirect_to :action => :index
elsif current_user.shop.valid?
    flash[:notice] = I18n.t 'shops.upgrade.must'
    redirect_to :action => :index
  else
    @product = Product.new
  end
end

Магазин теперь относится к типу 1 и имеет только 9 товаров, но всякий раз, когда я нажимаю ссылку "Новый продукт", я перенаправляюсь на / products с сообщением shops.upgrade.must.

Не знаю, похоже, что

account 

в shop.rb не возвращает правильное значение. Этот столбец имеет тип int (11), поэтому я думаю, он может возвращать только число, но все же ...

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