RailsCasts Pro episodes are now free!

Learn more or hide this

Matthieu Guillemot's Profile

GitHub User: mguillemot

Site: http://www.ankama.jp/

Comments by Matthieu Guillemot

Avatar

Usually, your client side will be a web browser that can execute JS code without any third-party library, so ExecJS is not needed in this case (and wouldn't work, since ExecJS needs a Ruby interpreter, that is not available in any standard web browser).

Avatar

In this case, I think Ryan just suggested you would use a Prawn::Document object inside your OrderPdf class, instead of inheriting from it. So for example, you would change:

ruby
class OrderPdf < Prawn::Document
  def initialize
    super
    text "Order goes here"
  end
end

into:

ruby
class OrderPdf
  def initialize
    @pdf = Prawn::Document.new
    @pdf.text "Order goes here"
  end

  def render
    @pdf.render
  end
end

(or use the delegate method mentionned by syath instead of writing your own render method)

In general, prefer composition to inheritance is considered good engineering practice because you control more tightly what your class exposes when you "use" an object rather than inheriting from it, so you have less surprises in the future.

For example, if a new version of Prawn renames the render function to render_document, you can just modify your own render method to use the new render_document one, instead of having to track every usage of render in your application. Or if you want to scrap Prawn and use another library, you can probably just modify your OrderPdf without rewriting a single line outside of it.

That's what we mean when we say that composition offer better encapsulation than inheritance.

Avatar
  1. Also means you could re-use the same JS file with another project. For example if you build a merchant hosting site where each of your users can create their own merchant site hosted by you, you could change easily who the payment is going to while using the same JS file for everyone.

  2. Some peculiarities of Ruby's parser (nothing to do with Rails). Without self, it would think you are trying to assign a local stripe_customer_token variable instead of using the implicitly defined self.stripe_customer_token= attribute writer.

Avatar

That would likely trigger a Stripe::InvalidRequestError when trying to Stripe::Customer.create( card: stripe_card_token) with your faked stripe_card_token, and thus prevent saving the subscription record.