即使没有持久化,Rails强制to_param返回一些内容

时间:2017-09-09 13:19:29

标签: ruby-on-rails mongoid ruby-on-rails-5 actionview mongoid6

我需要处理使用非持久数据构建的URL生成电子邮件视图的特定情况。

示例:假设我的用户可以创建帖子,并触发帖子创建通知电子邮件,我想向用户发送假帖子创建的示例。为此,我使用FactoryGirl.build(:post)并将其传递给我的PostMailer.notify_of_creation(@post)

在日常的Rails生活中,我们使用路由url_helpers作为参数传递模型本身,路由生成器将自动将模型转换为其ID以用于路由URL生成(在{{1路由助手将article_path(@article)转换为@article以构建@article.id网址。

我相信它在ActiveRecord中是一样的,但无论如何在Mongoid中,如果模型没有持久化,这种转换就会失败(这有点好,因为它可以防止生成可能与实际数据不对应的URL)

因此,在我的具体案例中,网址生成因模型未被保留而崩溃:

/articles/:id

崩溃
  

<%= post_url(@post_not_persisted) %>

有没有办法可以在非常具体的范围内绕过这个限制?否则,我可以将所有ActionView::Template::Error: No route matches {:action=>"show", :controller=>"posts", :post_id=>#<Post _id: 59b3ea2aaba9cf202d4eecb6 ...替换为resource_path(@model)或更好resource_path(@model.id.to_s),但这感觉不是正确的情况......

编辑:

主要问题是

@model.class.name

即使模型没有保留,我也需要强制Foo.new.to_param # => nil # whereas Foo.new.id.to_s # => "59b528e8aba9cf74ce5d06c0" 返回ID(或其他内容)。现在我正在寻找改进,看看我是否可以使用一个范围的monkeypatch,但如果你有更好的想法,请成为我的客人: - )

to_param

但是,在使用我的优化时,我似乎有一个小范围问题,因为这不会像预期的那样冒出url_helpers。它在控制台中使用te细化时可以正常工作(module ForceToParamToUseIdRefinement refine Foo do def to_param self.class.name + 'ID' end end end

1 个答案:

答案 0 :(得分:0)

我找到了一种使用动态方法覆盖的方法。我不是很喜欢它,但它完成了工作。我基本上是在测试期间使用的实例。

为了方便起见,我创建了一个类方法example_model_accessor,其基本上与attr_accessor类似,不包括setter修补对象的#to_param方法

def example_model_accessor(model_name)
  attr_reader model_name

  define_method(:"#{model_name}=") do |instance|
    def instance.to_param
      self.class.name + 'ID'
    end
    instance_variable_set(:"@#{model_name}", instance)
  end
end

然后在我的代码中我可以使用

class Testing
  example_model_accessor :message

  def generate_view_with_unpersisted_data
    self.message = FactoryGirl.build(:message)
    MessageMailer.created(message).deliver_now
  end
end

# views/message_mailer/created.html.erb
...
<%= message_path(@message) %> <!-- Will work now and output "/messages/MessageID" ! -->