具有数组属性的Ruby类
我在Ruby中有一个非数据库支持的类:具有数组属性的Ruby类,ruby,Ruby,我在Ruby中有一个非数据库支持的类: class User attr_accessor :countries end 我希望国家仅仅是一组ISO国家代码(美国、GB、CA、AU等),我不想构建一个单独的模型来容纳每个国家。有没有一种神奇的方法可以让Ruby理解:countries是一个数组并相应地处理它,或者我需要编写countries和countries=方法 我试着用user.countries=['US']设置countries数组,得到了一个NoMethodError。看起来co
class User
attr_accessor :countries
end
我希望国家仅仅是一组ISO国家代码(美国、GB、CA、AU等),我不想构建一个单独的模型来容纳每个国家。有没有一种神奇的方法可以让Ruby理解:countries
是一个数组并相应地处理它,或者我需要编写countries
和countries=
方法
我试着用user.countries=['US']设置countries数组,得到了一个NoMethodError。看起来
countries
应该是一个常量:
class User
COUNTRIES = %w(
AF AX AL DZ AS AD AO AI AQ AG AR AM AW AU AT AZ BS BH BD BB BY BE BZ BJ BM
BT BO BQ BA BW BV BR IO BN BG BF BI KH CM CA CV KY CF TD CL CN CX CC CO KM
CG CD CK CR CI HR CU CW CY CZ DK DJ DM DO EC EG SV GQ ER EE ET FK FO FJ FI
FR GF PF TF GA GM GE DE GH GI GR GL GD GP GU GT GG GN GW GY HT HM VA HN HK
HU IS IN ID IR IQ IE IM IL IT JM JP JE JO KZ KE KI KP KR KW KG LA LV LB LS
LR LY LI LT LU MO MK MG MW MY MV ML MT MH MQ MR MU YT MX FM MD MC MN ME MS
MA MZ MM NA NR NP NL NC NZ NI NE NG NU NF MP NO OM PK PW PS PA PG PY PE PH
PN PL PT PR QA RE RO RU RW BL SH KN LC MF PM VC WS SM ST SA SN RS SC SL SG
SX SK SI SB SO ZA GS SS ES LK SD SR SJ SZ SE CH SY TW TJ TZ TH TL TG TK TO
TT TN TR TM TC TV UG UA AE GB US UM UY UZ VU VE VN VG VI WF EH YE ZM ZW
).freeze
end
User::COUNTRIES.include? "US" #=> true
冻结
防止修改:
User::COUNTRIES.delete "US" #=> RuntimeError: can't modify frozen Array
更新
这里的问题是,您的国家阵列必须以某种方式保持。您提到的有很多
,因此Rails似乎参与其中。您可以使用ActiveRecord
的方法:
它在内部与YAML进行转换,因此users
表如下所示:
mysql> SELECT * FROM users;
+----+-------------------+---------------------+---------------------+
| id | countries | created_at | updated_at |
+----+-------------------+---------------------+---------------------+
| 1 | ---\n- US\n- CA\n | 2013-09-24 18:24:03 | 2013-09-24 18:24:03 |
+----+-------------------+---------------------+---------------------+
1 row in set (0,00 sec)
在Ruby中,变量的类型并不重要
attr\u accessor
只创建设置和返回实例变量的getter和setter方法<代码>@countries在这种情况下。您可以将实例变量设置为数组,或使用setter:
class User
attr_accessor :countries
def initialize
@countries = %w[Foo Bar Baz]
# Or...
self.countries = %w[Foo Bar Baz]
end
end
> puts User.new.countries
=> ["Foo", "Bar", "Baz"]
就个人而言,我更喜欢使用实例变量而不是self.xxx
;很容易忘记self.
位,最后设置了一个局部变量,而实例变量为nil
。我也觉得很难看
如果这些国家不会在不同的情况下发生变化,为什么不是一个常数呢
编辑/澄清
塔德曼的观点被很好地采纳了,例如。我不关心的环境仅限于小型的、自我控制的、独立的类。做出这些假设存在内在风险,这些风险的水平取决于项目。它是一个访问者;不管它是什么类型。如果你使用
attr\u accessor
这个,你将得到免费的countries
和countries=
:):)这个类需要如何“相应地对待它”,这与仅仅user.countries=[:gb,:au]不同
?attr\u accessor
提供了countries
和countries=
方法,但是没有什么可以阻止您将@countries
设置为数组以外的其他对象。如果您想执行数组操作,比如,您的问题似乎已经或多或少得到了回答。但是您指出的这个用例似乎更适合常量而不是访问器方法imho。如果您有attr\u访问器
时使用实例变量,那么如果您重写了getter或setter方法,可能会导致一些错误。如果你大量使用JavaScript,而这是绝对必要的,那么严格遵守添加self
的规则并不是什么大问题。@tadman正确。如果您使用的是attr_accessor
并覆盖了其中一个,我会说您做得不对。IMOattr_accessor
表明它是一个访问器,而不是一个执行其他逻辑的方法。它可以在子类中重写,但不能在父类中重写。做假设有点冒险。如果声明任何类型的访问器,即使实例变量可能相同,也应该使用它<代码>self.countries.push(“bla”)
不会work@TheRookierLearner我不知道你为什么这么想。你也可以制作一个类方法来总结:def self.countries;国家;结束
。这似乎毫无意义,但它允许子类在需要时重写该方法,并避免将此常量的结构暴露给需要访问数组的代码的其他部分。请参阅上面的注释。用户实际上应该拥有ISO代码完整列表的一个子集的所有权。对我的申请来说,有很多是多余的。
mysql> SELECT * FROM users;
+----+-------------------+---------------------+---------------------+
| id | countries | created_at | updated_at |
+----+-------------------+---------------------+---------------------+
| 1 | ---\n- US\n- CA\n | 2013-09-24 18:24:03 | 2013-09-24 18:24:03 |
+----+-------------------+---------------------+---------------------+
1 row in set (0,00 sec)
class User
attr_accessor :countries
def initialize
@countries = %w[Foo Bar Baz]
# Or...
self.countries = %w[Foo Bar Baz]
end
end
> puts User.new.countries
=> ["Foo", "Bar", "Baz"]