我正在编写一个充当量身定制表单的应用程序。
客户模型具有许多属性,这些属性以毫米为单位存储在数据库中。 由于此应用程序将在欧洲和美国使用,我将使用虚拟属性向用户显示数据的英寸和厘米版本。
例如,对于客户身高,我在我的模型中有这个:
def height_in_cm
height / 10
end
def height_in_cm=(height)
self.height = height.to_f * 10
end
def height_in_in
height * 0.039370
end
def height_in_in=(height)
self.height = height.to_f / 0.039370
end
这在我的_form视图中:
<% if @customer.measure_unit.eql? "imperial" %>
<%= f.input :height_in_in %></br>
<% else %>
<% if @customer.measure_unit.eql? "metric" %>
<%= f.input :height_in_cm %></br>
<% end %>
<% end %>
由于我说我有很多属性,我的客户模型文件变得非常长且非常容易出错。
是否有一种干燥方法可以缩短它?
答案 0 :(得分:1)
将这样的逻辑封装起来:
def display_height
case measure_unit
when 'imperial' then height_in_in
when 'metric' then height_in_cm
else height_in_in
end
end
然后您的观点就像这样:
<%= @customer.display_height %>
如果您在许多模型中使用这些相同的转换方法,请将其解压缩到如下模块:
module HeightConversions
def height_in_cm
height / 10
end
def height_in_in
height * 0.039370
end
def display_height
case measure_unit
when 'imperial' then height_in_in
when 'metric' then height_in_cm
else height_in_in
end
end
end
并在需要的模型中包含它:
class Customer
include HeightConversions
end
修改强>
好的,也许你需要更像这样的东西:
%w(neck waist arm).each do |name|
self.class_eval do
define_method :"#{name}_in_cm" do
self.send(name) / 10
end
define_method :"#{name}_in_cm=" do |n|
self.send("#{name}=", (n.to_f * 10))
end
define_method :"#{name}_in_in" do
self.send(name) * 0.03
end
define_method :"#{name}_in_in=" do |n|
self.send("#{name}=", (n.to_f / 0.039370))
end
end
end
这通常称为元编程。这是一篇关于在Rails中执行此操作的不同方法的简明文章: http://www.trottercashion.com/2011/02/08/rubys-define_method-method_missing-and-instance_eval.html
答案 1 :(得分:0)
我会让gem或javascript进行转换。像ruby-units这样的宝石可能有点矫枉过正,但为你想要的转换提供了持久的解决方案。
为了让javascript进行转换,这里有一些你可以添加到application.js的东西。您还可以使用“基线”概念在rails中干燥您的方法。
function convert_units(input, input_unit, output_unit) {
// Used to convert all units to similar intermediary unit. I used meters.
var inches_per_meter = 39.3701;
var sixteenths_per_meter = 629.9216;
var cm_per_meter = 100;
var mm_per_meter = 1000;
var intermediary = 0; //in meters
switch(input_unit)
{
case: "mm": intermediary = input * mm_per_meter;
break;
case: "cm": intermediary = input * cm_per_meter;
break;
case: "meter": intermediary = input;
break;
case: "inches": intermediary = input * inches_per_meter;
break;
case: "sixteenths": intermediary = input * sixteenths_per_meter;
break;
default: return "Input unit not correctly accomodated";
}
switch(output_unit)
{
case: "mm": return intermediary / mm_per_meter;
break;
case: "meter": return intermediary;
break;
case: "inches": return intermediary / inches_per_meter;
break;
case: "sixteenths": return intermediary / sixteenths_per_meter;
break;
case: "cm": return intermediary / cm_per_meter;
break;
default: return "Output unit not correctly accomodated";
}
}
然后在你的观点中
convert_units(@customer.height, 'inches', 'cm');