在Ruby中如果我只是分配一个局部变量.
sound = "bang".
Run Code Online (Sandbox Code Playgroud)
那是一种main.sound=("bang")方法吗?如果是这样,那个方法"sound ="在哪里以及如何被定义?或者这项任务如何运作?如果没有,实际发生了什么?
我知道对于一个setter方法你会说x.sound =("bang").并且您使用参数"bang"在对象"x"上调用方法"sound =".你正在创建一个实例变量"声音".
我可以想象所有这一切.但不是在"主"对象中分配变量时.据我所知,它不是Object类的实例变量......或者是它?我很困惑.
我从来没有找到一个很好的方法来做到这一点,所以我想我会问.
例如,在ActiveRecord模型中,数据库支持的属性会自动进行类型转换为适当的数据库支持类型.如果我有一个Category模型,它有几个属性的,说name和category_id,如果我是这样的:
Category.new(params[:category])
Run Code Online (Sandbox Code Playgroud)
Rails知道这name是一个String并且category_id是一个Integer.
假设我有几个我要验证的瞬态/合成属性,并且它们具有特定类型.我想从表单中提交它们,我希望它们根据它们的定义自动转换为String或Integer或Date(例如).
如果我要在Rails模型中声明一些内容,例如:
attr_accessor :some_number_variable
attr_accessor :some_date
Run Code Online (Sandbox Code Playgroud)
是否有一个内置的方式来告诉Rails"我想你前强制转换为整数,而后者的日期,当我走Category.new(params[:category])",只要params[:category][:some_number_variable]和params[:category][:some_date]提交给控制器的数据的一部分(我知道考虑到许多日期格式,Date示例可能有点棘手).
class Test
class << self
attr_accessor :some
def set_some
puts self.inspect
some = 'some_data'
end
def get_some
puts self.inspect
some
end
end
end
Test.set_some => Test
puts Test.get_some.inspect => Test nil
Run Code Online (Sandbox Code Playgroud)
在上面我可以找到自己作为测试本身但不返回some_data输出.
但是,当我按以下方式修改时,它返回预期的输出
class Test
class << self
attr_accessor :some
def set_some
puts self.inspect
self.some = 'some_data'
end
def get_some
puts self.inspect
self.some
end
end
end
Test.set_some => Test
puts Test.get_some.inspect => Test some_data
Run Code Online (Sandbox Code Playgroud)
有什么区别?
现在在第一个例子中,如果我将get some方法设置为
Test.some = 'new_data'
puts Test.some.inspect #=> new_data
Test.set_some
puts …Run Code Online (Sandbox Code Playgroud) 我正在使用Thinking Sphinx来运行搜索,我得到了合适的ActiveRecord模型.问题是,我想在每个模型上创建一个合适的链接路径和文本,然后通过AJAX以JSON的形式将信息发送到浏览器.我使用以下内容来构建这些链接属性:
在控制器中:
class FindController < ApplicationController
def tag_results
@results = ThinkingSphinx.search(params[:terms])
@results.each do |result|
result.build_ajax_response
end
respond_to do |format|
format.html
format.json { render :json => @results }
end
end
end
class TaggedItem < ActiveRecord::Base
attr_accessible :name
attr_accessor :search_link, :search_text
def build_ajax_response
self.search_link = Rails.application.routes.url_helpers.tagged_item_path(self.id)
self.search_text = self.name
end
end
Run Code Online (Sandbox Code Playgroud)
在模型中:
生成的json对象没有列出任何search_*属性,更不用说它们的值了.我尝试在方法中使用@search_link以及search_link .build_ajax_response
class FindController < ApplicationController
def tag_results
@results = ThinkingSphinx.search(params[:terms])
@results.each do |result|
result.build_ajax_response
end
respond_to do |format|
format.html
format.json { render :json => @results }
end … 我在我的用户模型中有这个代码:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates :email, :presence => true,
:uniqueness => { :case_sensitive => false },
:format => { :with => /\A[^@]+@[^@]+\z/ },
:length => 7..128
validates :password, :presence => true,
:confirmation => true,
:length => 6..128
private
def encrypt_password
return unless password
self.encrypted_password = BCrypt::Password.create(password)
end
end
Run Code Online (Sandbox Code Playgroud)
现在在我的控制器中,当我用一些用户字段更新时
@user.update_attributes(params[:user])
Run Code Online (Sandbox Code Playgroud)
即使没有在params散列中设置密码字段,也始终验证密码字段.我认为这是因为attr_accesor:密码总是在update_attributes上设置password ="".
现在我可以简单地跳过验证密码,如果它是一个空字符串:
validates :password, :presence => true,
:confirmation => true,
:length => 6..128,
:if => "password.present?"
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为它允许用户设置一个空密码.
在我想要更改的字段上使用update_attribute不是解决方案,因为我需要对该属性进行验证.如果我传入确切的参数
@user.update_attributes(params[:user][:fieldname])
Run Code Online (Sandbox Code Playgroud)
它不能解决问题,因为它还会触发密码验证. …
我理解instance_eval和之间的基本区别class_eval.我玩的时候发现的东西是奇怪的attr_accessor.这是一个例子:
A = Class.new
A.class_eval{ attr_accessor :x }
a = A.new
a.x = "x"
a.x
=> "x" # ... expected
A.instance_eval{ attr_accessor :y }
A.y = "y"
=> NoMethodError: undefined method `y=' for A:Class
a.y = "y"
=> "y" # WHATTT?
Run Code Online (Sandbox Code Playgroud)
怎么样:
attr_accessor我见过的每个例子都使用符号(:var)作为变量.
这是使用的要求attr_accessor,如果是,为什么?如果没有,为什么这是一种普遍的做法?
在Ruby中定义访问器时,简洁(我们都喜欢)和最佳实践之间可能存在紧张关系.
例如,如果我想在实例上公开一个值但禁止任何外部对象更新它,我可以执行以下操作:
class Pancake
attr_reader :has_sauce
def initialize(toppings)
sauces = [:maple, :butterscotch]
@has_sauce = toppings.size != (toppings - sauces).size
...
Run Code Online (Sandbox Code Playgroud)
但突然间我正在使用一个原始实例变量,这让我抽搐了.我的意思是,如果我需要在未来某一日期设定之前处理has_sauce,我可能需要做更多的重构不仅仅是重写访问.来吧,原始实例变量?布莱什.
我可以忽略这个问题并使用它attr_accessor.我的意思是,任何人都可以设置属性,如果他们真的想要; 毕竟,这就是Ruby.但后来我失去了数据封装的想法,对象的界面定义不太明确,系统可能更混乱.
另一种解决方案是在不同的访问修饰符下定义一对访问器:
class Pancake
attr_reader :has_sauce
private
attr_writer :has_sauce
public
def initialize(toppings)
sauces = [:maple, :butterscotch]
self.has_sauce = toppings.size != (toppings - sauces).size
end
end
Run Code Online (Sandbox Code Playgroud)
这完成了工作,但对于一个简单的存取器而言,这是一大块样板,而且非常坦率地说:ew.
那么有更好的,更Ruby的方式吗?
所以这出现在我的脑海里,想知道下面的一些事情发生时会发生什么.
class Test
def self.abc
attr_accessor :John
end
end
object = Test.new
puts "before calling class method abc: #{object.class.instance_methods(false)}"
Test.abc
puts "after calling class method abc: #{object.class.instance_methods(false)}"
Run Code Online (Sandbox Code Playgroud)
在这里我检查的是,以这种方式创建getter和setter方法.如果是这样,那些实例方法或类方法.首先,我创建一个新对象,然后查看该对象的实例方法.在下一行之后,我运行该class方法abc然后再次检查实例的方法object.当时只有我能看到这两种方法John和John=.这是怎么发生的?为什么运行类方法会动态地向已创建的对象添加方法?有人可以解释一下这个.
代码的输出是:
before calling class method abc: []
after calling class method abc: [:John, :John=]
Run Code Online (Sandbox Code Playgroud) 我在User模型中有这行代码:
attr_accessor :birthdate
Run Code Online (Sandbox Code Playgroud)
在同一个模型中,我有一个方法试图通过这样做来设置该生日:
self.birthdate = mydate
Run Code Online (Sandbox Code Playgroud)
其中mydate是Date对象.
我收到此错误: undefined method birthdate='
为什么会这样?是不是attr_accessor创建了一个setter和一个getter?
attr-accessor ×10
ruby ×7
validation ×2
accessor ×1
activerecord ×1
class-eval ×1
setter ×1
transient ×1