Austin Story

Ruby, Rails and Javascript Blog

Powered by Genesis

Confident Ruby

October 16, 2016 By Austin Story Leave a Comment

I just finished reading Confident Ruby for the second time and wanted to capture the lessons from it. The first time I read this book was (i think) beginning/mid 2013. I am really happy I went through it again, I learned some really good things to add to my toolbelt.

  1. Cast your inputs and outputs – In order to avoid constantly checking for Nil, Integer, Array, etc, just cast or munge the data you have into the format you need.  For instance, instead of returning nil, a single item or a collection, be nice and return Array(return_value).  It will help the user on the other side be more certain of what they are dealing with.  The oppositie is true when you are receiving data, cast it so that you are certain what you are dealing with and that you are handling that assertion of format in one place.
    1. There are several built in conversion methods, use the one that makes the most sense for the problem you are solving.  For instance, if your system depends on something being a float, cast it using Float(num_or_string) otherwise use the more gracious to_f.
  2. Prefer Fetch with Blocks – It seems like a great deal of work in web apps relates to dealing with hashes.  Instead of using the standard hash[‘x’], use hash.fetch(‘x’) { default_value_or_raise }.  You can even use the raise value for if the hash does not have a value to help you find the error when you run into it in the future.  hash.fetch(‘x’) { raise :this_symbol_is_easy_to_find }.  An added benefit of using blocks, is that they are not evaluated until the fetch fails, whereas if  you do hash.fetch(‘x’, expensive_operation).  It is evaled when the fetch executes.
  3. &&= – I use ||= constantly to memoize truthy values.  Advi demonstrates using the &&= operator to assign a value to a nested attribute if the first one is present.  For instance foo &&= foo.clone ensures that a foo exists before you call the clone on it.
  4. Segregate Actions – Your code is generally doing one of 4 things; Collecting Input, Performing Work, Delivering Output, Handling Failures.  Keep those separate and when you are done with one, be done with it.
  5. Replace String With Class – As best as you can, express domain logic using Classes.  Using strings or hashes is quick, but the class will help you clarify the domain and you have the side benefit of Polymorphism to handle a lot of switching.  A great example of this is a Parameter Object.  In the book you start with a drawing a point on a map to represent a location.  This quickly expands to a FuzzyPoint (a point with a radius around it) and a StarPoint.  The classes allow the encapsulation of all of the uniqueness of these.
    1. Yield Builder Objects (197) – Instead of locking users into an api implementation, allow for a block to be passed in and yield to the block in builders.  This allows them to configure stuff you may not have accounted for.   For instance, when you create a PointBuilder to create the things above.  If it accepts a block where you yield the point to it, you can accept things like PointBuilder.new(x: 5,y: 7) { |p| p.maginitude = 75 }.  Your PointBuilder automatically can handle SOOO many more cases.
  6. Document Assumptions – When assuming something will be a certain way, document it using code.  I.e. cast float using Float or if you want a collection use Array.  This will increase clarity for you and other programmers.
  7. Receive Policies Instead of Data (206) – When you have different ways you want to handle edge cases (for instance, return false, log differently, raise in some cases), instead of passing in flags for :ignore_errors, :log_stuff, :raise prefer to accept a block that specifies what you want to happen.  The in the rescue area you can do something like if block_givin? then yield(thing, error) else raise end
  8. Call back instaed of returning (211)  – A callback on success is more meaningful than a true false return value.  In the book we have a import_purchase method that is used a lot.  That import_purchase cna accept a block and on_success, on_reduntant, on_fail yield itself to the block along with a the message (on_success, etc).  The block passed in then defines what happens on those cases.  Completely inverts the control so that instead of hard wiring in what is going to happen, you dictate it view the block that is passed in.
  9. Catch and Throw – This is a concept i see somethings, always obscurely.  But you can create a block catch(:done) method end.  Then if you throw(:done) it will go up the call stack until there is something that catches it and continue executing below it.

Filed Under: Books, Ruby Tagged With: book review, confident ruby, ruby

Creating private_attr_reader in Ruby

February 16, 2016 By Austin Story Leave a Comment

In my current project we use a whole lot of plain ruby objects. One day I was looking at them and noticed that we follow this pattern for just about everything.
[ruby]
module MyModule
class MyClass
attr_reader :params

def initialize(params:)
@params = params
end
def call
params.do_things
end
end
end
[/ruby]

The params attr_reader is used so that we don’t have to use @params throughout the object. I got used to this format and like that my ide looks better without all the @vars everywhere. But I think that it is a false contract. The public method for our objects is `call` and is all that we ever intend for someone else to use. However, the user of attr_reader says that this is a public method.

To get around this, i decided to add a quick patch so that we could still have the use of the params method locally for instance variable lookup but keep it private so that noone accidentally starts using it only for us to change it in the future.

Here is the patch I added to Object. I didn’t go all the way down to Kernel because all of our objects inherit from Object.

[ruby]
class Object
def self.private_attr_reader(*args)
args.each do |arg|
define_method(arg) { instance_variable_get("@#{arg}") }
private arg
end
end
end
[/ruby]

After adding this patch to Object we can now do this in our object and var1 and var2 would both be have attr_readers that are private to the class.

[ruby]
private_attr_reader :var1, var2
[/ruby]

Filed Under: Ruby, Ruby on Rails Tagged With: Metaprogramming, monkey patching, ruby

Digging Stripe using Map and Select

January 7, 2016 By Austin Story Leave a Comment

Had a client who had a bad subscription plan in their stripe account that was applied over a year ago.  They have enough volume that it didn’t make sense to go through the web admin to clean up the data so we cleaned it up using the Stripe ruby gem.  Here is the process that I went through to discover the correct commands to issue.

To start, this was a promotional amount that was only applied for a few days in january for the start of the year.  So off the bat I wanted to narrow it down to the related customers.

[ruby]
users = User.where("created_at >= ?", 1.year.ago).where("created_at <?", 330.days.ago)

paying_users = users.where.not(stripe_customer_id: nil)

customer_ids = users.map(&:stripe_payment_id)
[/ruby]

Now that we had the customer ids from tripe i wanted to see what the data looked like

[ruby]
Stripe::Customer.retrieve(customer_ids.first)
[/ruby]

the Stripe::Customer that is returned looks and acts like an open struct or hashie mash. So you can call methods on it similar to javascript objects in order to get values of a key that is in the object.

I didn’t know the specific name of the subscription (didn’t have web access). So needed to discover what it was called. I remembered it had the word special in it.

Next is to find the specific customers that we need to look at

[ruby]
stripe_customers = customer_ids.map{|c| Stripe::Customer.retrieve(c)}
stripe_customers.select(&:subscription).map{|c| c.subscription.plan.id}.uniq
[/ruby]

This returns an array of [‘premium’, ‘othersubscriptions’,….,’newyearsspecial’]. So i know that it is the newyearsspecial that i need to update.

[ruby]
special_customers = stripe_customers.select(&:subscription).select{|c| c.subscription.plan.id == ‘newyearsspecial’}

special_subscriptions = special_customers.map{|c| c.subscription.id}

special_subscriptions = special_customers.map(&:subscription)
[/ruby]

The next part is a little vague, in the documentation it says to set the ‘at_period_end’ parameter to true in order to delete it and keep it active until the end of the subscription, so i just did both.

[ruby]
special_subscriptions.each do |subscription|
subscription.at_period_end = true
subscription.delete(at_period_end: true)
end
[/ruby]

Now all of the subscriptions will expire at the end of the year, Yeah!

Filed Under: Ruby on Rails, Stripe Tagged With: API, ruby, Stripe, Stripe APi, Stripe ruby

  • 1
  • 2
  • 3
  • Next Page »

Categories

  • AngularJS
  • Books
  • Devise
  • Elasticsearch
  • ES6
  • Information Security
  • Integrations
  • Javascript
  • Linux
  • Minitest
  • PhoneGap
  • Programming
  • React
  • Redux
  • Ruby
  • Ruby on Rails
  • Stripe
  • Testing
  • Theory
  • TypeScript
  • Uncategorized
  • Vue
  • Webpack