Class: Facebooker::Rails::Publisher

Inherits:
Object
  • Object
show all
Defined in:
lib/facebooker/rails/publisher.rb

Overview

ActionMailer like module for publishing Facbook messages

To use, create a subclass and define methods Each method should start by calling send_as to specify the type of message Valid options are :email and :notification, :user_action, :profile, :ref, :publish_stream

Below is an example of each type

class TestPublisher < Facebooker::Rails::Publisher
  # The new message templates are supported as well
  # First, create a method that contains your templates:
  # You may include multiple one line story templates and short story templates
  # but only one full story template
  #  Your most specific template should be first
  #
  # Before using, you must register your template by calling register. For this example
  #  You would call TestPublisher.register_publish_action
  #  Registering the template will store the template id returned from Facebook in the 
  # facebook_templates table that is created when you create your first publisher
  def publish_action_template
    one_line_story_template "{*actor*} did stuff with {*friend*}"
    one_line_story_template "{*actor*} did stuff"
    short_story_template "{*actor*} has a title {*friend*}", render(:partial=>"short_body")
    short_story_template "{*actor*} has a title", render(:partial=>"short_body")
    full_story_template "{*actor*} has a title {*friend*}", render(:partial=>"full_body")    
    action_links action_link("My text {*template_var*}","{*link_url*}")
  end

  # To send a registered template, you need to create a method to set the data
  # The publisher will look up the template id from the facebook_templates table
  def publish_action(f)
    send_as :user_action
    from f
    story_size SHORT # or ONE_LINE or FULL
    data :friend=>"Mike"
  end

  # Provide a from user to send a general notification
  # if from is nil, this will send an announcement
  def notification(to,f)
    send_as :notification
    recipients to
    from f
    fbml "Not"
  end

  def email(to,f)
    send_as :email
    recipients to
    from f
    title "Email"
    fbml 'text'
    text fbml
  end
  # This will render the profile in /users/profile.fbml.erb
  #   it will set @user to user_to_update in the template
  #  The mobile profile will be rendered from the app/views/test_publisher/_mobile.erb
  #   template
  def profile_update(user_to_update,user_with_session_to_use)
    send_as :profile
    from user_with_session_to_use
    recipients user_to_update
    profile render(:file=>"users/profile.fbml.erb",:assigns=>{:user=>user_to_update})
    profile_action "A string"
    mobile_profile render(:partial=>"mobile",:assigns=>{:user=>user_to_update})
end

  #  Update the given handle ref with the content from a
  #   template
  def ref_update(user)
    send_as :ref
    from user
    fbml render(:file=>"users/profile",:assigns=>{:user=>user_to_update})
    handle "a_ref_handle"
end

  #  Publish a post into the stream on the user's Wall and News Feed.
  def publish_stream(user_with_session_to_use, user_to_update, params)
    send_as :publish_stream
    from  user_with_session_to_use
    target user_to_update
    attachment params[:attachment]
    message params[:message]
    action_links params[:action_links]
  end

To send a message, use ActionMailer like semantics

TestPublisher.deliver_action(@user)

For testing, you may want to create an instance of the underlying message without sending it

TestPublisher.create_action(@user)

will create and return an instance of Facebooker::Feeds::Action

Publisher makes many helpers available, including the linking and asset helpers

Defined Under Namespace

Classes: Email, FacebookTemplate, ImageHolder, InvalidSender, Notification, Profile, PublishStream, PublisherController, Ref, UnknownBodyType, UnspecifiedBodyType, UserAction

Constant Summary collapse

ONE_LINE =

story sizes from the Facebooker API

1
SHORT =
2
FULL =
4

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePublisher

Returns a new instance of Publisher.



107
108
109
110
111
112
113
114
# File 'lib/facebooker/rails/publisher.rb', line 107

def initialize
  @from                 = nil
  @full_story_template  = nil
  @recipients           = nil
  @action_links         = nil
  @controller           = PublisherController.new(self)
  @action_links         = nil
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object



346
347
348
349
350
351
352
353
354
# File 'lib/facebooker/rails/publisher.rb', line 346

def method_missing(name,*args)
  if args.size==1 and self._body.respond_to?("#{name}=")
    self._body.send("#{name}=",*args)
  elsif self._body.respond_to?(name)
    self._body.send(name,*args)
  else
    super
  end
end

Instance Attribute Details

#_bodyObject

Returns the value of attribute _body.



273
274
275
# File 'lib/facebooker/rails/publisher.rb', line 273

def _body
  @_body
end


335
336
337
338
339
340
341
342
343
344
# File 'lib/facebooker/rails/publisher.rb', line 335

def action_links(*links)
  if self._body and self._body.respond_to?(:action_links)
    self._body.send(:action_links,*links)
  end
  if links.blank?
    @action_links
  else
    @action_links = *links
  end
end

#one_line_story_templatesObject

Returns the value of attribute one_line_story_templates.



218
219
220
# File 'lib/facebooker/rails/publisher.rb', line 218

def one_line_story_templates
  @one_line_story_templates
end

#short_story_templatesObject

Returns the value of attribute short_story_templates.



218
219
220
# File 'lib/facebooker/rails/publisher.rb', line 218

def short_story_templates
  @short_story_templates
end

Class Method Details

.add_template_helper(helper_module) ⇒ Object

:nodoc:



573
574
575
576
# File 'lib/facebooker/rails/publisher.rb', line 573

def add_template_helper(helper_module) #:nodoc:
  master_helper_module.send :include,helper_module
  include master_helper_module
end

.controller_pathObject



558
559
560
# File 'lib/facebooker/rails/publisher.rb', line 558

def controller_path
  self.to_s.underscore
end

.default_url_optionsObject



116
117
118
# File 'lib/facebooker/rails/publisher.rb', line 116

def self.default_url_options
  {:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
end

.helper(*args) ⇒ Object



562
563
564
565
566
567
568
569
570
571
# File 'lib/facebooker/rails/publisher.rb', line 562

def helper(*args)
  args.each do |arg|
    case arg
    when Symbol,String
      add_template_helper("#{arg.to_s.camelcase}Helper".constantize)
    when Module
      add_template_helper(arg)
    end
  end
end

.inherited(child) ⇒ Object



579
580
581
582
583
584
585
# File 'lib/facebooker/rails/publisher.rb', line 579

def inherited(child)
  super
  child.master_helper_module=Module.new
  child.master_helper_module.__send__(:include,self.master_helper_module)
  child.send(:include, child.master_helper_module)
  FacebookTemplate.clear_cache!
end

.method_missing(name, *args) ⇒ Object



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
# File 'lib/facebooker/rails/publisher.rb', line 533

def method_missing(name,*args)
  should_send = false
  method = ''
  if md = /^create_(.*)$/.match(name.to_s)
    method = md[1]
  elsif md = /^deliver_(.*)$/.match(name.to_s)
    method = md[1]
    should_send = true            
  elsif md = /^register_(.*)$/.match(name.to_s)
    return FacebookTemplate.register(self, md[1])
  else
    super
  end
      
  #now create the item
  (publisher=new).send(method,*args)
  case publisher._body
  when UserAction
    publisher._body.template_name = method
    publisher._body.template_id ||= FacebookTemplate.bundle_id_for_class_and_method(self,method)
  end
  
  should_send ? publisher.send_message(method) : publisher._body
end

.register_all_templatesObject



507
508
509
510
511
512
513
514
# File 'lib/facebooker/rails/publisher.rb', line 507

def register_all_templates
  all_templates = instance_methods.grep(/_template$/) - %w(short_story_template full_story_template one_line_story_template) 
  all_templates.each do |template|
    template_name=template.sub(/_template$/,"")
    puts "Registering #{template_name}"
    send("register_"+template_name)
  end
end

.register_all_templates_on_all_applicationsObject



500
501
502
503
504
505
# File 'lib/facebooker/rails/publisher.rb', line 500

def register_all_templates_on_all_applications
  Facebooker.with_all_applications do
    puts "Registering templates for #{Facebooker.api_key}"
    register_all_templates
  end
end

.respond_to?(method_symbol, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


525
526
527
528
529
530
531
# File 'lib/facebooker/rails/publisher.rb', line 525

def respond_to?(method_symbol, include_private=false)
  if match = /^(create|deliver|register)_([_a-z]\w*)/.match(method_symbol.to_s)
    instance_methods.include?(match[2])
  else
    super(method_symbol, include_private)
  end
end

.unregister_inactive_templatesObject



516
517
518
519
520
521
522
523
# File 'lib/facebooker/rails/publisher.rb', line 516

def unregister_inactive_templates
  session = Facebooker::Session.create
  active_template_ids = FacebookTemplate.all.map(&:bundle_id)
  all_template_ids = session.active_template_bundles.map {|t| t["template_bundle_id"]}
  (all_template_ids - active_template_ids).each do |template_bundle_id|
    session.deactivate_template_bundle_by_id(template_bundle_id)
  end
end

Instance Method Details



377
378
379
# File 'lib/facebooker/rails/publisher.rb', line 377

def action_link(text,target)
  {:text=>text, :href=>target}
end

#announcement_notification?(from, body) ⇒ Boolean

Returns:

  • (Boolean)


393
394
395
# File 'lib/facebooker/rails/publisher.rb', line 393

def announcement_notification?(from,body)
  from.nil? and body.is_a?(Notification)
end

#default_url_optionsObject



120
121
122
# File 'lib/facebooker/rails/publisher.rb', line 120

def default_url_options
  self.class.default_url_options
end

#from(*args) ⇒ Object



283
284
285
286
287
288
289
# File 'lib/facebooker/rails/publisher.rb', line 283

def from(*args)
  if args.size==0
    @from
  else
    @from=args.first
  end        
end

#full_story_template(title = nil, body = nil, params = {}) ⇒ Object



317
318
319
320
321
322
323
# File 'lib/facebooker/rails/publisher.rb', line 317

def full_story_template(title=nil,body=nil,params={})
  if title.nil?
    @full_story_template
  else
    @full_story_template=params.merge(:template_title=>title, :template_body=>body)
  end
end

#image(src, target) ⇒ Object



373
374
375
# File 'lib/facebooker/rails/publisher.rb', line 373

def image(src,target)
  ImageHolder.new(image_path(src),target.respond_to?(:to_str) ? target : url_for(target))
end

#initialize_template_class(assigns) ⇒ Object



448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/facebooker/rails/publisher.rb', line 448

def initialize_template_class(assigns)
  template_root = "#{RAILS_ROOT}/app/views"
  controller_root = File.join(template_root,self.class.controller_path)
  #only do this on Rails 2.1
  if ActionController::Base.respond_to?(:append_view_path)
    # only add the view path once
    unless ActionController::Base.view_paths.include?(controller_root)
      ActionController::Base.append_view_path(controller_root) 
      ActionController::Base.append_view_path(controller_root+"/..") 
    end
    view_paths = ActionController::Base.view_paths
  else
    view_paths = [template_root, controller_root]
  end
  returning ActionView::Base.new(view_paths, assigns, self) do |template|
    template.controller=self
    template.extend(self.class.master_helper_module)
    def template.request_comes_from_facebook?
      true
    end
  end
end

#loggerObject

nodoc needed for actionview



435
436
437
# File 'lib/facebooker/rails/publisher.rb', line 435

def logger
  RAILS_DEFAULT_LOGGER
end

#one_line_story_template(str) ⇒ Object



325
326
327
328
# File 'lib/facebooker/rails/publisher.rb', line 325

def one_line_story_template(str)
  @one_line_story_templates ||= []
  @one_line_story_templates << str
end

#profile_update?(body) ⇒ Boolean

Returns:

  • (Boolean)


385
386
387
# File 'lib/facebooker/rails/publisher.rb', line 385

def profile_update?(body)
  body.is_a?(Profile)
end

#recipients(*args) ⇒ Object



275
276
277
278
279
280
281
# File 'lib/facebooker/rails/publisher.rb', line 275

def recipients(*args)
  if args.size==0
    @recipients
  else
    @recipients=args.first
  end
end

#ref_update?(body) ⇒ Boolean

Returns:

  • (Boolean)


389
390
391
# File 'lib/facebooker/rails/publisher.rb', line 389

def ref_update?(body)
  body.is_a?(Ref)
end

#render(opts) ⇒ Object

nodoc delegate to action view. Set up assigns and render



441
442
443
444
445
# File 'lib/facebooker/rails/publisher.rb', line 441

def render(opts)
  opts = opts.dup
  body = opts.delete(:assigns) || {}
  initialize_template_class(body.dup.merge(:controller=>self)).render(opts)
end

#request_comes_from_facebook?Boolean

use facebook options everywhere

Returns:

  • (Boolean)


125
126
127
# File 'lib/facebooker/rails/publisher.rb', line 125

def request_comes_from_facebook?
  true
end

#requires_from_user?(from, body) ⇒ Boolean

Returns:

  • (Boolean)


381
382
383
# File 'lib/facebooker/rails/publisher.rb', line 381

def requires_from_user?(from,body)
  ! (announcement_notification?(from,body) or ref_update?(body) or profile_update?(body))
end

#send_as(option) ⇒ Object



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/facebooker/rails/publisher.rb', line 292

def send_as(option)
  self._body=case option
  when :action
    Facebooker::Feed::Action.new
  when :story
    Facebooker::Feed::Story.new
  when :templatized_action
    Facebooker::Feed::TemplatizedAction.new
  when :notification
    Notification.new
  when :email
    Email.new
  when :profile
    Profile.new
  when :ref
    Ref.new
  when :user_action
    UserAction.new
  when :publish_stream
    StreamPost.new
  else
    raise UnknownBodyType.new("Unknown type to publish")
  end
end

#send_message(method) ⇒ Object

Raises:



397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/facebooker/rails/publisher.rb', line 397

def send_message(method)
  @recipients = @recipients.is_a?(Array) ? @recipients : [@recipients]
  if from.nil? and @recipients.size==1 and requires_from_user?(from,_body)
    @from = @recipients.first
  end
  # notifications can 
  # omit the from address
  raise InvalidSender.new("Sender must be a Facebooker::User") unless from.is_a?(Facebooker::User) || !requires_from_user?(from,_body)
  case _body
  when Facebooker::Feed::TemplatizedAction,Facebooker::Feed::Action
    from.publish_action(_body)
  when Facebooker::Feed::Story
    @recipients.each {|r| r.publish_story(_body)}
  when Notification
    (from.nil? ? Facebooker::Session.create : from.session).send_notification(@recipients,_body.fbml)
  when Email
    from.session.send_email(@recipients, 
                                       _body.title, 
                                       _body.text, 
                                       _body.fbml)
  when Profile
   # If recipient and from aren't the same person, create a new user object using the
   # userid from recipient and the session from from
   @from = Facebooker::User.new(Facebooker::User.cast_to_facebook_id(@recipients.first),Facebooker::Session.create) 
   @from.set_profile_fbml(_body.profile, _body.mobile_profile, _body.profile_action, _body.profile_main)
  when Ref
    Facebooker::Session.create.server_cache.set_ref_handle(_body.handle,_body.fbml)
  when UserAction
    @from.session.publish_user_action(_body.template_id,_body.data_hash,_body.target_ids,_body.body_general,_body.story_size)
  when Facebooker::StreamPost
   @from.publish_to(_body.target, {:attachment => _body.attachment, :action_links => @action_links, :message => _body.message })
  else
    raise UnspecifiedBodyType.new("You must specify a valid send_as")
  end
end

#short_story_template(title, body, params = {}) ⇒ Object



330
331
332
333
# File 'lib/facebooker/rails/publisher.rb', line 330

def short_story_template(title,body,params={})
  @short_story_templates ||= []
  @short_story_templates << params.merge(:template_title=>title, :template_body=>body)
end