3

I'm working on a Railtie(gem) for embedding videos like YouTube, Vimeo etc.

In this gem i want to have a view helper, so that i can call embed_video(embeddable, width, height)

So i have created the helper as a helper, and it works, but i would like to refactor it to use partials to make it cleaner, but i'm finding it hard to do this.

The helper:

module ViewHelpers
  def embed_video(embeddable, width, height)
    if embeddable.video_on_youtube?
      content_tag :iframe, nil, width: width, height: height,
        src: "//www.youtube.com/embed/#{embeddable.video_id}",
        allowfullscreen: true, frameborder: 0
    elsif embeddable.video_on_vimeo?
      content_tag :iframe, nil, width: width, height: height,
        src: "//player.vimeo.com/video/#{embeddable.video_id}",
        webkitallowfullscreen: true, mozallowfullscreen: true,
        allowfullscreen: true, frameborder: 0
    elsif embeddable.video_on_dailymotion?
      content_tag :iframe, nil, width: width, height: height,
        src: "//www.dailymotion.com/embed/video/#{embeddable.video_id}",
        webkitallowfullscreen: true, mozallowfullscreen: true,
        allowfullscreen: true, frameborder: 0
    elsif embeddable.video_on_veoh?
      %Q{
        <object width='#{width}' height='#{height}' id='veohFlashPlayer' name='veohFlashPlayer'>
          <param name='movie' value='http://www.veoh.com/swf/webplayer/WebPlayer.swf?version=AFrontend.5.7.0.1446&permalinkId=#{embeddable.video_id}&player=videodetailsembedded&videoAutoPlay=0&id=anonymous'></param>
          <param name='allowFullScreen' value='true'></param>
          <param name='allowscriptaccess' value='always'></param>
          <embed src='http://www.veoh.com/swf/webplayer/WebPlayer.swf?version=AFrontend.5.7.0.1446&permalinkId=#{embeddable.video_id}&player=videodetailsembedded&videoAutoPlay=0&id=anonymous' type='application/x-shockwave-flash' allowscriptaccess='always' allowfullscreen='true' width='#{width}' height='#{height}' id='veohFlashPlayerEmbed' name='veohFlashPlayerEmbed'>        </embed>
        </object>
      }.html_safe
    #
    # And more providers...
    #
  end
end

With the use of partials i want to write it like this:

module ViewHelpers
  def embed_video(embeddable, width, height)
    if embeddable.video_on_youtube?
      render 'youtube', embeddable: embeddable, width: width, height: height
    elsif embeddable.video_on_veoh?
      render 'veoh'#...etc
    end
  end
end

My attempted solution:

  • Create a folder: lib/embeddable/partials

  • Add partial for veoh: lib/embeddable/partials/_veoh.html.erb

Add view paths in railtie.rb

module Embeddable
  class Railtie < Rails::Railtie
    # ...load view helpers... #

    initializer 'embeddable.add_autoload_paths', :before => :set_autoload_paths do |app|
      app.config.autoload_paths << app.root.join("lib/embeddable/partials").to_s
    end

    # My attempt at adding the partials to the view path
    initializer 'embeddable.add_view_paths', :after => :add_view_paths do |app|
      ActiveSupport.on_load(:action_controller) do
        append_view_path app.root.join("lib/embeddable/").to_s
      end
    end
  end
end

When i try to render the view i get the following error:

ActionView::MissingTemplate: Missing partial partials/veoh with {:locale=>[:nb], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :rabl, :haml]}. Searched in:
  * "/home/me/Arbeid/the_application/app/views"
  * "/home/me/.rvm/gems/ruby-2.1.0/gems/kaminari-0.15.1/app/views"
  * "/home/me/Arbeid/the_application/lib/embeddable"
Pål
  • 958
  • 2
  • 13
  • 18
  • Partials shouldn't be used in a helper. If you want to call other partials you're probably better off using a partial instead of a helper. – Max Williams May 20 '14 at 10:20
  • It would be perfect for me in this case though. Why shouldn't i use a partial in a helper? And how can i include a partial in a railtie? – Pål May 20 '14 at 10:29
  • It's just not what they are for. Helpers are for returning a small amount of html. – Max Williams May 20 '14 at 10:44
  • That said, you should still be able to do it with `render :partial => "path/to/youtube", :locals => {:embeddable => embeddable, :width => width, :height => height}` – Max Williams May 20 '14 at 10:47
  • That's what i thought too, but it only looks for the partial in the app/view folder of the app that is using the gem. I tried adding lib/embeddable to view_paths(see example above) but unfortunately i did not manage to get it working. – Pål May 20 '14 at 11:46

2 Answers2

3

After a lot of trail and error i managed to get it working. This is what i had to do:

I changed this:

initializer 'embeddable.add_view_paths', :after => :add_view_paths do |app|
  ActiveSupport.on_load(:action_controller) do
    append_view_path app.root.join("lib/embeddable/").to_s
  end
end

Into this:

initializer 'embeddable.add_view_paths', :after => :add_view_paths do |app|
  ActiveSupport.on_load(:action_controller) do
    append_view_path "#{Gem.loaded_specs['embeddable'].full_gem_path}/lib/embeddable"# <- this is the change
  end
end

Now i can render partials from the helper like this:

render 'partials/youtube', id: video_id, width: width, height: height
Pål
  • 958
  • 2
  • 13
  • 18
  • I thought this through again and: why are you not putting views in app/views in engine? – Mike Szyndel May 21 '14 at 10:36
  • The reason i did not create an engine is simply because the gem is really small. It only contains a concern, and the code i have posted in this question. I thounght making it an engine with models, controllers etc. would be kind of overkill. – Pål May 21 '14 at 10:53
1

I know it's not a direct answer to your question but instead of reinventing a wheel I would rather propose using AutoHTML gem:

auto_html is a Rails extension for transforming URLs to appropriate resource (image, link, YouTube, Vimeo video,...). It's the perfect choice if you don't want to bother visitors with rich HTML editor or markup code, but you still want to allow them to embed video, images, links and more on your site, purely by pasting URL.

https://github.com/dejan/auto_html

To answer your question directly I think the problem is that you mixed up autoload path and view path.

You should have

app.config.autoload_paths << app.root.join("lib/embeddable").to_s

and

append_view_path app.root.join("lib/embeddable/partials").to_s
Mike Szyndel
  • 10,461
  • 10
  • 47
  • 63
  • Thanks! This is probably what i should have done. I'm interested in learning to build my own engines and railties though, so figuring out how to solve my problem would be awesome! – Pål May 20 '14 at 12:47
  • I tried changing this, however, the path ends up being within the project the gem has been included in, and not the actual gem's path(and can't find the partial). This is what i get: "/home/me/Arbeid/my_application/lib/embeddable/partials". This is what i wish to get: "/home/me/.rvm/gems/ruby-2.1.0/gems/my_gem/lib/embeddable/partials" – Pål May 20 '14 at 19:49
  • Oh, so you should set it in a gem then. – Mike Szyndel May 20 '14 at 20:31
  • Wait, I'm lost. You say a gem now, but what you wrote in original question is a module in lib. Those are two different things, aren't they? – Mike Szyndel May 20 '14 at 20:32
  • Oh, sorry. All the code shown here is from the gem. The gem is a railtie. So the view_paths is being set inside of the gem. – Pål May 21 '14 at 07:20
  • I found a solution and created an answer for it. I had to get the absolute path of the gem. I thought for sure it would use the gem's path by default, since i referenced from within it. – Pål May 21 '14 at 10:12
  • Thanks for great help, and tips for the auto_html gem - worthy of an upvote! – Pål May 21 '14 at 13:27