开发者

Is there a method I can use across controllers and if so, how do I use it?

I have several controllers that take an instance of different classes each (Email, Call, Letter, etc) and they all have to go through this same substitution:

@email.message.gsub!("{FirstName}", @contact.first_name)
@email.message.gsub!("{Company}", @contact.company_name) 
@email.message.gsub!("{Colleagues}", @colleagues.to_sentence)
@email.message.gsub!("{NextWeek}", (Date.today + 7.days).strftime("%A, %B %d"))
@email.message.gsub!("{ContactTitle}", @contact.title )

So, for example, @call.message for Call, @letter.message for Letter, etcetera.

This isn't very dry. I tried the following:

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time

  def message_sub(asset, contact, colleagues)
    asset.message.gsub!("{FirstName}", contact.first_name)
    asset.message.gsub!("{Company}", contact.company_name) 
    asset.message.gsub!("{Colleagues}", colleagues.to_sentence)
    asset.message.gsub!("{NextWeek}", (Date.today + 7.days).strftime("%A, %B %d"))
    asset.message.gsub!("{ContactTitle}", contact.title )
  end
end

So in, say, the Letter Controller have this:

@letter = Letter.find(params[:letter]) #:letter was passed as a hash of the letter instance

message_开发者_Go百科sub(@letter, @contact, @colleagues)

@contact_letter.body = @letter.body

But the above doesn't work.


To answer your question directly, you want a module. You can put it in your lib directory.

module MessageSubstitution

  def message_sub(asset, contact, colleagues)
    asset.message.gsub!("{FirstName}", contact.first_name)
    asset.message.gsub!("{Company}", contact.company_name) 
    asset.message.gsub!("{Colleagues}", colleagues.to_sentence)
    asset.message.gsub!("{NextWeek}", (Date.today + 7.days).strftime("%A, %B %d"))
    asset.message.gsub!("{ContactTitle}", contact.title )
  end

end

Then in your controller

class MyController < ApplicationController

  include MessageSubstitution


  def action

    ...

    message_sub(@letter, @contact, @colleagues)

  end

end

However, as some have already pointed out, this is probably better at the model level:

module MessageSubstitution

  def substituted_message(contact, colleagues)
    message.gsub("{FirstName}", contact.first_name).
           gsub("{Company}", contact.company_name).
           gsub("{Colleagues}", colleagues.to_sentence).
           gsub("{NextWeek}", (Date.today + 7.days).strftime("%A, %B %d")).
           gsub("{ContactTitle}", contact.title )
  end

end

Which you would then include at the model level, and then call in your controller like @letter.substituted_message(@contact, @colleagues)

However, I'm a little confused that what you posted didn't work, though. If it's defined on ApplicationController it should work. Module-based solution still better IMO.


I think we are missing information needed to fix this problem. Check out section 3 of this guide: Debugging Rails Applications

Step through your code and check the variables at each point to see if they are what you expect.

When you have time, be sure to read the whole guide. It provides an invaluable set of tools for Rails programming.

As a side note, the code you have provided feels like it is more suited to be in the model than in the controller. Your models may be a good candidate for Single Table Inheritance or your models are so much alike that you can condense them into a more generalized model that covers what you need. If either of these options are a good fit, you could move message_sub out of the controller and into the model.


The problem may lie in the fact that gsub! works on the instance of the String object returned by ActiveRecord. To notify ActiveRecord of an attribute change, you should call the method message=(value). So, your method would be like this:

def message_sub(asset, contact, colleagues)
  asset.message = asset.message.
      gsub("{FirstName}", contact.first_name).
      gsub("{Company}", contact.company_name).
      gsub("{Colleagues}", colleagues.to_sentence).
      gsub("{NextWeek}", (Date.today + 7.days).strftime("%A, %B %d")).
      gsub("{ContactTitle}", contact.title )
end

(I took some artistic license to chain the gsub method, but it's all in your tastes)


It's not clear if the question is about reusing a method across the controller (as the title suggests) or the best way to do message templates. To reuse the method across the controller , I guess you already answer the question yourself by using a common class. However as Awgy suggested this bit could better be in the Model than in the Controller.

To template message you can use ERB rather gsub or just 'eval' your string (if you use #{} instead of {} in your message)

firstName=contact.first_name
company = company_name
...
asset.message = eval "\"#{asset.message}\""

(You might even be able to pass directly contact as a 'bindings' to the eval function.


Personally, I wouldn't delegate this to the controller, isn't this something that the Presenter Pattern is for?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜