shirt.rb
[ id, size, color ]
作为输入,我得到的值params[:size]
等于例如170. shirts
table size
列中的数据以格式存储 - "160-180"
(所以它是一个字符串)
我如何预先形成查询:
Shirt.where("parse_first_number(size) > ? AND parse_second_number(size) < ?", params[:size], params[:size])
答案 0 :(得分:3)
我强烈建议您通过使用两个值来改进数据库架构:min_size
和max_size
。然后,您可以进行更简单的查询:
Shirt.where("min_size <= ? AND max_size >= ?", params[:size], params[:size])
您提出的问题可能,但要复杂得多。
答案 1 :(得分:0)
这基本上是您存储的数据列类型的问题。如果存储字符串,则数据库无法将其转换为数字并进行比较。一种方法是使用另一个支持范围的数据库,但更方便的方法是使用两列(size_from,size_to)或存储大小的命名变量并在代码中保持值常量,如
class Shirt
SIZES = [ { large: (160..180), ... ].freeze
答案 2 :(得分:0)
让我重申这是糟糕的设计,您应该使用单独的列。
据说,没有数据库无关的解决方案。这是postgres的一个。请注意,这是丑陋和缓慢的:
size_in_bounds_condition = <<-SQL
CAST(split_part(coalesce(size, '0-0'), '-', 1) AS integer) < ?
AND
CAST(split_part(coalesce(size, '0-0'), '-', 2) AS integer) > ?
SQL
Shirt.where(size_in_bounds_condition, params[:size], params[:size])
答案 3 :(得分:0)
也是丑陋和缓慢(这是技术债务的本质)。但如果衬衫表很小,它现在可能会起作用。
shirt_size = 170
shirts = [
{id:1, size:"160-180", color:"red"},
{id:2, size:"180-200", color:"red"},
{id:3, size:"160-180", color:"blue"}
]
shirts.select do |s|
min, max = s[:size].split("-").map(&:to_i)
max > shirt_size && min < shirt_size
end
=> [{:id=>1, :size=>"160-180", :color=>"red"}, {:id=>3, :size=>"160-180", :color=>"blue"}]
答案 4 :(得分:0)
Rails在Range
hash condition中接受#where
作为值:
sizes = "160-180" # this comes from your DB I presume
min, max = sizes.split('-').collect(&:to_i)
Shirt.where(size: min..max)
如果你想检查所提供的参数是否在范围内,那就简单了:
def valid_size?
sizes = "160-180" # again from your shirt in DB
min, max = sizes.split('-').collect(&:to_i) # when you get tired of this line, it means it's time to refactor it
# collapse the following into one line
params[:size] && # check for presence
params[:size].between?(min, max) && # check if in range
params[:size] # I guess you want to return the size if valid, rather than only a boolean
end
# Alternative checks, that don't need the presence check:
# - (min..max).member?(params[:size])
# - (min..max).include?(params[:size])
# I choose what I find more explicit and readable
最后,我同意您应该迁移数据库,将最小和最大大小存储为两个单独的整数。像往常一样,为您的函数编写测试,然后编写最简单的解决方案以使测试变为绿色。在那一点上,无论如何,继续并重构你的数据库:)
# migration
def up
add_column :shirts, :min_size, :integer
add_column :shirts, :max_size, :integer
Shirt.find_each do |shirt|
min, max = shirt.size.split('-').collect(&:to_i) # for the last time :)
shirt.min_size = min
shirt.max_size = max
shirt.save!
end
remove_column :shirts, :size
end
def down
add_column :shirts, :size, :string
Shirt.find_each do |shirt|
size = "#{shirt.min_size}-#{shirt.max_size}"
shirt.size = size
shirt.save!
end
remove_column :shirts, :min_size, :integer
remove_column :shirts, :max_size, :integer
end