Hack hack hack...

An open journal-- some of it written for you, but most of it is for me.

Presenter Objects

From our PR thread

  • A presenter object is a simply a PORO (plain ol’ ruby object), constructed by the controller out of the data of one or more models, whose attributes serve the view layer. So in our case we give a view a LessonPresenter that has a css_class attribute and remove all decision making from the view layer (which is the ideal goal).

  • It’s not a “service” object, it’s a presenter so it would go in the presenters folder. This is also sometimes called a “view model” or a “view object”. The word “presenter” is overloaded a lot.

  • This an interesting read on a few model refactoring patterns:

  • So instead of a collection of Lessons at the view level, you’d be dealing with a collection of LessonPresenters or similar. Alternatively, you can just put that method on the lesson object itself, which is simpler and more straightforward but not strictly Single Responsibility Principle/Seperation of Concerns/Model View Controller compliant. tradeoffs.

Is it a terrible idea to have LessonPresenter inherit from Lesson?

A: Strictly speaking in terms of OO, inheritance describes an “is-a” relationship, and you can’t say that a lessonpresenter is a lesson, so introducing an inheritance chain is probably inappropriate. There is some duplication to this pattern. Typically a viewmodel exposes only the attributes needed to satisfy the needs of the view, and you’d fill them in from the corresponding model on construction.

While this seems on the surface to violate DRY (and be duplicate work), i’d argue that it’s no more repetition than creating factories with the same attributes as models. Separate objects for separate purposes.

You could get away with hanging a lesson off of the presenter so that you could access it at the view level, but that’s a law of demeter violation and breaks encapsulation.

You could do the method_missing bit and delegate to the object. that’s slick and rubyish. Where that falls apart though is implementing this pattern across more than one model. Because we’re not really building a “presenter for a lesson”, we’re building a presentation object for a view that represents the model data behind it.

Already this answer is complicated, but there’s just always a lot of decisions that go into making architectural choices. It may be the case that for this one thing, creating a method on the Lesson itself is the “simplest thing that could possibly work” and satisfies one of our tenets of agile, and then we delay the big architectural choice until we need a second or third thing.

I support whichever choice you make (probably) as long as you have unit tests to support later refactoring :smile_cat:

Okrs for Engineers

Notes

  • lead developer’s OKRs mostly product focused
    • and their product responsibilites become one piece of their bonus compensation (also would include overall company success (no bonus is the company didn’t make money)).
  • break to feature or objective into smaller product pieces for engineers if possible.

OKRs for engineers below lead devs are difficult. Goals become more task oriented. E.g.

  • 2 ruby meetups a month
  • satisfactory 360 feedback
  • biweekly one on ones (address concerns of manager)

Cucumber Trick Shots

Remove unused step definitions

  • cucumber --dry-run -f stepdefs will show a list of all unused step definitions via.

Rspec Keywords

Feedback on my misuse of rspec keywords (and context in particular):

  • Context describes an execution context, or an arrangement of the system, not an action.
  • It helps to always think of context blocks in terms of “when …” and it is usual to begin contexts with a when.

The layout is like this:

  • describe some system/class/function
    • context “when condition A is true about the system”
      • it “behaves thusly”
    • context “when condition B is true about the system”
      • it “behaves thusly”

A classic example might be:

1
2
3
4
5
6
7
8
9
10
11
12
13
describe SomeController do
  describe "GET new" do
    context "when logged in" do
      it "renders this page"
    end
    context "when admin" do
      it "renders this other page"
    end
    context "when visitor" do
      it "redirects to login"
    end
  end
end

Rails 4 CSRF Handling

Setup

Right now we are building “Ironboard” (title is WIP) – an application that makes makes consuming prework a breeze for students and creating and organizing prework a breeze for teachers. This application is going to fit into a workflow that kicks off when a student pays their deposit. The short version is that another internal app is going to ping an endpoint on Ironboard, which internally will generate an email invitation and enroll that student in course so that the instructor can track their progress.

CSRF

I’ve read the rails security guide. I searched stackoverflow and quite frankly the documentation for handling CSRF in rails 4 is sucky. Alex Coco seems to have done the most documentation here. Buried in all of this is the proper way to handle cross-domain requests in 2011:

Users can override this behaviour by overriding handle_unverified_request in their own controllers.

Most answers that are out there have to do with disabling the protect_from_forgery method in a specfic controller for a specific action. This hides csrf vulnerability, but I’m not sure that disabling token authenticity makes things any better. Why use protect_from_forgery except: :ping_from_registrar when we could use the handle_unverified_request

We ended up using:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Api::FooController < ApplicationController
  skip_before_action :authenticate_user!

  private
  def handle_unverified_request
    authenticate_token || render_unauthorized
  end

  def authenticate_token
    authenticate_with_http_token do |token, options|
      token.eql?(ENV['API_TOKEN'])
    end
  end

  def render_unauthorized
    self.headers['WWW-Authenticate'] = 'Token realm="Application"'
    render json: 'Bad credentials', status: 401
  end

I think this is pretty awesome.

This was helpful as was this.

User Stories

Each user story should INVEST

I - Independent The user story should be self-contained, in a way that there is no inherent dependency on another user story. N - Negotiable User stories, up until they are part of an iteration, can always be changed and rewritten. V - Valuable A user story must deliver value to the end user. E - Estimable You must always be able to estimate the size of a user story. S - Sized appropriately or Small User stories should not be so big as to become impossible to plan/task/prioritize with a certain level of certainty. T - Testable The user story or its related description must provide the necessary information to make test development possible.

Iteration 0 -> is foundational work that is performed prior to development starting.

Feyonce

cancan’s bitmask

  • bitmask

  • by the way, it appears that cancan has been abandoned. We ended up rolling out our authorization.

devise

  • You can override the default behaviour by creating an after_sign_in_path_for via

Switch to omniauth

  • we made a major overhaul by switching to omniauth rather than using the devise email & password.
    • As per the omniauth wiki I needed to rebuild many of the paths that devise had created for us via the registerable and Database Authenticatable modules and reconfigure the appropriate controllers as well.
    • To its credit, the Devise::TestHelpers, type: :controller held up through the transition, which was a big help.

Bundle clean is the jam

  • bundle clean --force
  • bundle update Saved my @ss.

Before block versus let in rspec

  • use let to define all of the dependent objects, and to use before do to setup needed configuration or any mocks/stubs needed by the examples. via the comments section

Transient Factory Girl Properties

I needed a way to pass in some parameters into my factory. Enter transient properties.

The Eventual Code
1
2
3
4
5
6
7
8
9
10
11
factory :track_with_lessons do
  ignore do
    lesson_count 3
    topic_count 2
  end

  after(:create) do |track, evaluator|
    evaluator.topic_count.times { track.add_topic(create(:topic_with_lessons, lesson_count: evaluator.lesson_count))}
    track.save!
  end
end

A gotcha: The getting started readme was outdated so I was trying to use transient do which was not working. It appears that this will be fixed in the next release…

Capybara within block

When searching for an element with a div like within('div#first.drawer') do it truly means within, not like this can be the same element you are looking for, it has to be nested inside this element.

Testing with JSON

Found this to be a good place to start but I couldn’t get his method to actually work.

What he did
1
2
3
4
5
6
7
it "updates empty summary field" do
  @incoming_params[:id] = @dvd.id
  @incoming_params[:summary] =  'some summary'
  post 'entry/update', @incoming_params.to_json
  @entry.reload
  expect(@entry.summary).to eq 'some summary'
end
This is what worked for me
1
2
3
4
5
6
7
8
9
10
describe 'POST #topic_order' do
  it 'saves a new topic order' do
    sign_in_teacher
    track = create(:track_with_lessons)
    original_order = track.topic_order
    post :topic_order, "data"=> {"topic_order"=>"#{track.topic_order.last},#{track.topic_order.first}", "track_id"=>"#{track.id}"}, format: :json
    track.reload
    expect(track.topic_order).to eq original_order.reverse
  end
end

Service Objects Versus Concerns

I wrote this last May. Obviously, @scottcreynolds doesn’t think it sunk in.

We were writing a URL sanitizer that stripped the user’s URL input of http:// and www to store in the DB. Because we were using it for multiple models. I had viewed this “stipper” method as a behavior and thus had thought it belonged in the the DHH blessed concerns folder.

Scott disagreed:

A concern or mixin should describe a behavior that is being given to the object. That’s the “able” nomenclature. A behavior is something like “it can support tags” or “it can be authenticated with a devise token”.

What I should have seen was this is a utility method. He writes:

What was being created here is a utility or service method, intended to be used across any entity in the system that chooses to sanitize a url. This is not a behavior that the object has. Yes, you could go so far as to say “this object can sanitize its urls” but that’s a bit of semantic gymnastics when what we’re really describing is a service object - something that provides a service to any part of the system that requires it. In this case, scrubbing user input.

Something that may have helped me futher understand this was thinking about who was responsible for this sanitization. Is the Event object responsible for url sanitization?

It might seem like a fine hair to split, but if we examine further, we see that we weren’t really adding a common behavior to the event and admin_user classes.

The parseable module as designed only handled the case where the thing it was being mixed into had a field called website. Including it in event would have done absolutely nothing because that field doesn’t exist. What an event does have, however, is a registration_link. Already, we can see that we haven’t truly identified a common behavior so much as a common need - hence a service object.

Finally, just in the naming we can tell that we’re not really describing what we mean. If a class includes a module parseable, that include line, in English, reads an admin user is parseable. To me that means something significantly different than before save, strip some characters out of a field. The module being described didn’t do what it claimed to do by its name.

These things seem small, but they’re extremely important to care about because code bases grow and all you have in a dynamic language is your tests and your naming to help you understand the system a year from now. I could show you a rails project I just came into where no care was given to naming and structure, and you could spend days following the labyrinth of modules and classes and end up hoping the Minotaur finds you and eats you and spares you the hassle of figuring out what’s going on.

So in short, use concerns when extracting common behavior (active record finders, authentication, etc). Use service objects when extracting common needs.

Finally, a note on tests. It’s great we’re doing the cucumber, and doing it well, but we still need tests at model and controller levels too. If you make a new class/module it should have a test file and some tests.

Pow Config

I had a bunch of issues getting pow up and running after I upgraded to Mavricks. I ended up not installing via the curl method that the 37signals suggests as it wasn’t recognizing my rbenv and was running on my system ruby. So I uninstalled and tried it with homebrew, which required a different path in my .powconfig file. Just like the troubleshooter said it would via the github issue, this worked.

Final code: export PATH="/usr/local/opt/rbenv/shims:/usr/local/opt/rbenv/bin:$PATH"

Boom! Smack! Pow!

Cucumber With Scott

The point of BDD is to build a system form a perspective of a user, rather than just as a developer.

Login

As a partner, I need to be able to login, so that I can update my upcoming events.

Need to deliver a story and prove that it works.

An integration test is any test that cross the boundries of a system

Why cucumber

  • Gherkin language for feature files
  • rspec for tests
  • capybara to drive the browser

The tools are the same just when with gherkin thrown on top - cucumber is platform and language agnostic

So a problem I have is when to test built in features of the framework or gem.

Given, When, Then

  • same as Arrage, Act, Assert (which is what ALL tests do) in people talk

  • Arrage

    let(:something) {do_something}

1
2
3
before do
  arrange_things
end
  • Act, and Assert
1
2
3
4
it "does something when I do this" do
  do_a_thing #=> act
  expect(that_thing).to eq(something) #=> assert
end

Misc

  • user regex in the step file if you are going to reuse it
  • acceptance tests should be used to test large swatches rather than every permuation

tags

  • @pause like a binding
  • @wip won’t run unless specified to run
  • custom tags work too, so even then you’d run it with cucumber -t @jonas
  • or you can run multiple tags at one time, e.g. cucumber --tags @billing,@important