RAILS:自定义功能在哪里阻止

时间:2016-05-26 14:09:17

标签: sql ruby-on-rails ruby where

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]) 

5 个答案:

答案 0 :(得分:3)

我强烈建议您通过使用两个值来改进数据库架构:min_sizemax_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