Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 创建没有参数参数的新Ruby字符串帮助器_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails 创建没有参数参数的新Ruby字符串帮助器

Ruby on rails 创建没有参数参数的新Ruby字符串帮助器,ruby-on-rails,ruby,Ruby On Rails,Ruby,我真的很难想出这个问题的措辞,但本质上,我想这样做: model = MyModel.new model.title = "foo bar" model.title.to_id #=> "foo_bar" 我有一个用于MyModel的ActiveRecord类 class MyModel < ActiveRecord::Base def to_id(str) str.downcase.gsub(" ", "_") end end 但那不是很好 我知道我以前见过这种

我真的很难想出这个问题的措辞,但本质上,我想这样做:

model = MyModel.new
model.title = "foo bar"
model.title.to_id #=> "foo_bar"
我有一个用于MyModel的ActiveRecord类

class MyModel < ActiveRecord::Base
  def to_id(str)
    str.downcase.gsub(" ", "_")
  end
end
但那不是很好

我知道我以前见过这种方法的例子,我就是找不到它们


Halp any?

您应该查看其中的函数,特别是在您的示例中,我将使用(扩展的)String类中存在的下划线方法

然后,要覆盖访问器,可以执行以下操作:

model.to_id(model.title)
def title_id
  read_attribute(:title).underscore
end

我想这就是您想要的。

您可以使用模块通过方法扩展特定的对象实例

module ToId
  def to_id
    self.downcase.gsub " ", "_"
  end
end

class MyClass
  def title=(value)
    value.extend ToId
    @title = value
  end

  def title
    @title
  end
end

m = MyClass.new
m.title = "foo bar"

puts m.title        #=> foo bar
puts m.title.to_id  #=> foo_bar
由于传递到.title=方法的值是一个字符串,因此当我们使用ToId模块扩展字符串时,模块方法中的“self”是一个字符串。因此,我们可以直接访问传递到.title=方法的字符串,并且可以直接操作它


这一切都是在不必直接修改String类的情况下完成的。我们只是扩展了表示标题的特定实例。

我相信真正的Ruby解决方案是基于元编程的。如果你感兴趣,我强烈推荐你这本书(20美元)

顺便说一下,上面提出的解决方案可能不会起作用,因为重写列访问器并没有那么简单

因此,我建议您创建一个在模型定义中使用的类方法,如下所示:

class MyModel < ActiveRecord::Base
  # adds to_id to the following attributes
  ideize :name, :title
end

红宝石规则

这可能对模型不起作用-在简单类上完全起作用,但在从ActiveRecord::Base继承的类上不起作用(这是@drmanitoba的情况)
# 
# extends the ActiveRecord with the class method ideize that
# adds to_id method to selected attributes
#
module Ideizer
  module ClassMethods
    def ideize(*args)
      # generates accessors
      args.each do |name|
        define_method("#{name}") do
          # read the original value
          value = read_attribute(name)
          # if value does not contain to_id method then add it
          unless value.respond_to?(:to_id)
            # use eigen class for the value
            class << value
              def to_id
                self.downcase.gsub " ", "_"
              end
            end
          end
          # return the original value
          value
        end
      end
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

# extend the active record to include ideize method
ActiveRecord::Base.send(:include, Ideizer)
require 'spec_helper'

describe MyModel do
  before :each do
    @mod = MyModel.new(:name => "Foo Bar",
                       :title => "Bar Bar",
                       :untouched => "Dont touch me")
  end

  it "should have to_id on name" do
    @mod.name.respond_to?(:to_id).should be_true
    @mod.name.to_id.should eql "foo_bar"
  end

  it "should have to_id on title" do
    @mod.title.respond_to?(:to_id).should be_true
    @mod.title.to_id.should eql "bar_bar"
  end

  it "should NOT have to_id on untouched" do
    @mod.untouched.respond_to?(:to_id).should be_false
  end

  it "should work with real model" do
    @mod.save!
    @mod.name.to_id.should eql "foo_bar"

    # reload from the database
    @mod.reload
    @mod.name.to_id.should eql "foo_bar"
  end

end