Blog

Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts

Friday, June 20, 2014

Talk: Don't Commit Your Secrets

On Tuesday this week, I presented a talk to Montreal.rb on keeping your application secrets safe. Posted below is the video, slides and some follow-up questions during and after the presentation. Enjoy!

Video


Slides


Questions

How can I remove a secret from your Git repository?
GitHub has an excellent post on how to do this: Remove sensitive data. However, if you have committed a secret to your repository which has been push to a remote, then consider that secret compromised. You will need to reset the secret (i.e. create a new API key) and configure your application using the techniques described above.

How can I keep my secrets safe with an application pre-Rails 4.1?
Check out these options:

  • foreman: recommended - any Rack app
  • dotenv: great for plain old Ruby Gems too
  • figaro: YAML
  • capistrano: linking to a configuration file in production

Monday, October 7, 2013

Rails: undefined method `action' for YourController:Class

You will receive this error if you have created your controller class manually (i.e. without the Rails generators) and have not inherited from ApplicationController. For example


This is easily fixed by adding ApplicationController as the parent. Note the change on line #1.

Sunday, February 12, 2012

Heads up: Use spork-rails if you want to use spork 1.0rc in your Rails project

If you are using Spork 1.0rc in your Rails project and wondering why your controllers etc are not reloading, it's because this functionality has been extracted to the spork-rails plugin gem. Remove the spork reference from your Gem file and add 'spork-rails' instead. spork-rails will include spork 1.0rc as a dependency. This follows the convention for other gems such as rspec-rails and factory_girl_rails. Note spork-rails follows the versioning of minor Rails versions. For example, the current version is 3.2.0, compatible with Rails 3.2.x down to 3.0.0.

Saturday, October 22, 2011

Rails is Not Your Application

Background: The Beginnings of My Obsession with Application Architecture and Domain Modelling

Last year I was involved in my most complex Ruby on Rails application to date that is now 23K lines of model code, 14K lines of controller code, and 4.5K lines of lib code. You get the point, let's now worry about the view code. It was during this project that I observed the pain of working within the bounds of how we typically build Rails applications. Did I mention it was slow to develop and test? During that contract and ever since, I have been obsessing about application architecture and domain modelling.

Establish an Application Interface with a Service Layer

During the time I was working on said application, I introduced the concept of Services (in the early stages I called them managers). Although a lot of domain logic was pushed into the models, there was too much application logic in the controllers. Services, co-ordinating domain models, allowed me to extract that application logic to really keep the controllers thin. I'm not sure exactly sure what prompted me to start using Service objects, but after the fact I found references to them in Martin Fowler's Patterns of Enterprise Application Architecture (P of EAA). Other frameworks such as Grails also use Services, it even has a generator for them. Services resolves the discussion (started here) on where to trigger email notifications. Add them to your Services.

In P of EAA, Randy Stafford defines the Service Layer as:

"Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation."

And in a way, this definition helped me recognize another frustration I was having with how I (and most of the Rails community) was developing with Rails. There was no explicit application. Or rather, it was hard to define what the application was and hard to know how to interact with it. The application had no interface. My application was a ball of ActiveRecord objects.

Lots of Activity in the Rails Community Regarding Domain Modelling

I haven't been the only one thinking about application architecture and domain modelling. I'm not a unique snowflake. Others in our community have too: Mike Dietz from ThoughtWorks introduce me to DCI at RailsConf 2011Andrzej Krzywda has been blogging about it before that, and Jim Gay has recently been blogging about it on this side of the pond. On another tact, Corey Haines has been been selling fast tests over the last few months. Hidden in that sales pitch of course, is a way to extract domain logic. Talking of extracting domain logic, Steve Klabnick has illustrated some practical examples.

These guys have kept me busy! I've been quietly researching this topic for over a year now. You can check out some of my tags on Delicious:

Extracting the Application from the Framework

Ok, time to finish up this post. All of the efforts describe above have been with the purpose of managing the application and domain logic in the software we build. It benefits us with faster tests and code that clearly communicates it's intent. And although the Service Layer was helping me define an interface to my application, I was only using them when my controllers methods/actions were getting heavy with application logic. Then last night, I watched the latest release of Clean Code from Uncle Bob that highlights the need to extract your application from the framework you use (he's been teasing me for a while on this topic). With my previous experience with Services, and my interest in DCI, Uncle Bob's guidance was the piece I was missing.

After taking his example pseudo code, and turning it into some Ruby/Rails example (more like snippet) I gleefully tweeted:

"Rails is not your application. It might be your views and data source, but it's not your application. Put your app in a Gem or under lib/."

I really like this approach a lot, the ability to test your application outside of the Rails stack is huge, and viewing Rails as a method to deliver my application will change the way I write code. Anyway here is the code that triggered the Tweet (see below). It's not polished, it doesn't execute, it's not 100% right, but boy it's got me thinking. It uses Services to represent Use Cases of the application, and roles containing domain logic that is mixed in contextually, extracted into a Gem, delivered via Rails. If you not a fan of the Gem idea, keep it name spaced under your lib directory.

Update: A clarification on putting your application in lib. I certainly don't mean to put it directly in lib. Name space it, lib/your_application; e.g. lib/pay_roll.

Now that I have let the code out of the bag, expect some more posts on this topic in the future where I work through and describe this code (and related ideas) in more detail.



Written by .

Saturday, July 30, 2011

Gotcha with testing expected params with Bourne/Mocha in Rails Controller

This is something that always trips me up using Bourne (a fork of Mocha, a Ruby mocking and stubbing library) to test expected params in a Rails Controller. Take this spec:

context "with filter" do
  before do
    get :index, :search => {:brand_id => '1'}
  end

  it 'should find latest search results' do
    SearchResult.should have_received(:latest).with('brand_id' => '1')
  end
end

This test fails, but what if I tried this:

context "with filter" do
  before do
    get :index, :search => {:brand_id => '1'}
  end

  it 'should find latest search results' do
    SearchResult.should have_received(:latest).with(:brand_id => '1')
  end
end

This will fail. Note I am now checking the parameters passed using symbols for the keys. I receive the following error:


Failure/Error: SearchResult.should have_received(:latest).with(has_entry(:brand_id => '1'))
     expected exactly once, not yet invoked: SearchResult(id: integer, search_id: integer, body: text, source: text, url: string, created_at: datetime, updated_at: datetime).latest(has_entry(:brand_id => '1'))

This is because the params that are passed to the controller have keys as strings rather than symbols:

{'brand_id' => '1'}

So what's the solution? I could actually use HashWithIndifferentAccess which gives access to a Hash using strings or symbols for keys. This is in fact the class that is used for the params hash in the controller:

it 'should find latest search results' do
    SearchResult.should have_received(:latest).with(HashWithIndifferentAccess.new(:brand_id => '1'))
  end

Or, as a standard practice, when dealing with parameters passed to a controller within a spec, always use strings:

context "with filter" do
  before do
    get :index, 'search' => {'brand_id' => '1'}
  end

  it 'should find latest search results' do
    SearchResult.should have_received(:latest).with('brand_id' => '1')
  end
end

I think this is a lot simpler, cleaner. Interestingly, I didn't pass the brand_id as a Fixnum:

before do
    get :index, 'search' => {'brand_id' => 1}
  end

I would have got the same error:

Failure/Error: SearchResult.should have_received(:latest).with('brand_id' => 1)
     expected exactly once, not yet invoked: SearchResult(id: integer, search_id: integer, body: text, source: text, url: string, created_at: datetime, updated_at: datetime).latest('brand_id' => 1)

As the brand_id is present in the hash as a String, not a Fixnum.

Tuesday, July 26, 2011

Run a SQL query within Ruby on Rails

ActiveRecord::Base.connection.execute(your_sql_statement)

Monday, April 4, 2011

Looking for a Montréal-based Ruby on Rails developer?

Admittedly, I have been booked for a while now and haven't had any time to take on any projects. So where does one go if they are looking for Ruby on Rails developers located in Montréal? I would recommend checking out Working with Rails.

You might like to do a keyword search for Montréal or browse for developers located in Canada. I hope this helps your search for developers.

Saturday, April 2, 2011

A script for a Ruby on Rails Blog in 15 minutes

Early in the new year I made the switch to Vim from Textmate. I needed a lot of practice so I replicated the Rails screen-cast for a blog in 15 minutes produced by Ryan Bates over and over again. It was a great way to get familiar with Vim after years of Textmate editing. I wrote up a script based on that screen-cast to aid my practice, and I have also found it useful in quickly demoing Rails to a newbie. The script itself won’t make sense without viewing the screen-cast, but a good reminder of the steps if you find yourself in the same situation.

  • Create a new rails application
  • Start and verify server is running
  • Generate Post (title, body) scaffold
  • Demonstrate adding, updating Posts
  • Add validation rule to Post
  • Demonstrate adding an invalid post
  • Refactor posts/show view into partial
  • Refactor posts/index to use partial
  • Demonstrate in browser
  • Demonstrate XML (curl http://localhost:3000/posts.xml)
  • Add JSON format for Posts
  • Demonstrate JSON (curl http://localhost:3000/posts.json)
  • Add atom format (posts/index.atom.builder)
  • Add auto_discover_link_tag to layout
  • Add basic authentication to PostsController
  • Demonstrate in browser
  • Add Comment scaffold (body)
  • Don’t forget to update routes
  • Demonstrate routes (rake route)
  • Add list of comments to posts/show
  • Create comments partial
  • Add comments form to posts/show
  • Clear out CommentsController
  • Add create action (but use #build instead of #create!)
  • Create does not save, show off debugger
  • Demonstrating save comment in debugger
  • Change build method to #create!
  • Update comments form to use AJAX
  • Update comments controller to use AJAX
  • Demonstrate fall back without Javascript enabled
  • Create automated test for posting comments
  • Review with broken test
  • Review console by updating a post title, add comment

Here are the various 15 minute blog screen-casts for the different versions of Rails:

Friday, April 1, 2011

Rails server hangs on startup with Dalli Gem and Memcached

If your using Dalli and Memcached, ensure you are running the latest version of Memcached (at least 1.4 or greater) otherwise when starting Rails, the server will hang. You can upgrade Memcached easily enough with MacPorts (if that's what you're using):

sudo port upgrade memcached

If you haven't installed memached using MacPorts before and just have the version shipped on OSX, then do an install:

sudo port install memcached

Reference: http://www.mikeperham.com/2010/08/30/dalli-memcached-for-ruby/

Sunday, February 6, 2011

4 Things I Assert in Rails Controller Tests

  1. ActiveRecord Calls (using mocking)
  2. Assigns
  3. Flash
  4. Responses

And if the response content type is not going to be HTML I will test that as well.

Saturday, February 5, 2011

Cucumber Rails: undefined local variable or method `node'

I've been stung by this a couple of times so it's time to add it to my blog. This exception is raised when Cucumber follows a link using the click_link Capybara method. An example of the error:

When I follow "Add brand"                      # features/step_definitions/web_steps.rb:33
      undefined local variable or method `node' for # (NameError)
      ./features/step_definitions/web_steps.rb:35:in `block (2 levels) in '
      ./features/step_definitions/web_steps.rb:14:in `with_scope'
      ./features/step_definitions/web_steps.rb:34:in `/^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/'
      features/manage_brand.feature:14:in `When I follow "Add brand"'

This has been report in the following places:

The solution is to either remove the following line from env.rb:

require 'cucumber/capybara-javascript-emulation'

or better yet, simply bundle the Gem from the 'master' branch. Add this to your Gemfile:

group :development, :test do
  gem 'cucumber-rails', :git => 'git://github.com/aslakhellesoy/cucumber-rails.git'
  # other gems...
end

Important Note: You must regenerate your env.rb using rails g cucumber:install otherwise you will receive the following error:

no such file to load -- cucumber/rails/active_record (LoadError)

Saturday, January 29, 2011

Reminder: Restful controllers do not need to map one-to-one to models (in Rails)

The central concept of REST is the resource, which is a datastructure representing one or more business objects.

Source: http://nicksda.apotomo.de/2010/10/rails-misapprehensions-crud-is-not-rest/

Friday, January 14, 2011

Never use rescue blindly

On a recent project I was horrified to see various inline rescues. Here are three examples:

# Example 1
def friend_recommended_picture
  friend.recommended_picture rescue ""
end

# Example 2
params[:search][:skip_conversion] = true rescue nil

# Example 3
item_image = Product.find_by_id(product_id).images.find(:first, :conditions => 'attachment_file_name like "%example.jpg"').attachment.url(:mini) rescue ''

In all of these examples I the author is protecting themselves from a NoMethodError with a NilClass.

My preference is to always use the try method (provided in Rails 2.x and standard in Ruby 1.9):

# Example 1
def friend_recommended_picture
  friend.try(:recommended_picture) # returns nil if friend is nil
end

In Rails, this can be cleaned up using the delegate class method:

delegate :recommended_picture, :to => :friend, :allow_nil => true, :prefix => true

For the second example I would prefer this, although there is a little more code involved (clarity over cleverness):

# Example 2
params[:search][:skip_conversion] = true if params[:search]

And for the final example, well this is a bit of a mess. Let's clean up the call:

item_image = item_image(Product.find(product_id))

And encapsulate the various scopings within the correct classes.

# products_helper.b
def item_image(product)
 product.example_image.try(:attachment) {|attachment| attachment.url(:mini) }
end

# models/post.rb
def example_image
  images.examples.first
end

# models/images.rb
named_scope :examples, :conditions => 'attachment_file_name like "%example.jpg"'

This last example illustrates well that the careless use of rescue nil is a symptom of other issues such as poor encapsulation.

There are plenty of examples of using rescue such as on Ruby Inside:

h = { :age => 10 }
h[:name].downcase                         # ERROR
h[:name].downcase rescue "No name"        # => "No name"

This still makes me feel dirty inside. Yes it is working on a Hash, but what if h becomes a more complex object, then that rescue could be obscuring other exceptions. My preference would be:

h[:name].try(:downcase) || "No name"

Jay Fields also has an interesting use for inline rescue. One of the commenters mentions "its important to use them judiciously." I suspect the inline rescue is a victim of cargo culting and 99% of the time there is a better solution.

Thursday, January 13, 2011

Interfacing with Web Services? Checkout Tammer Saleh's "Coding for Failure"

Last year when interfacing with several Web services for a project I found Tammer Saleh's "Coding for Failure" indispensable. Although it was presented two years ago, it's far from out of date.

You can check it out on the Confreaks website and download the slides from here (the link on Tammer's website is broken).

Specifically I found Tammer's summary of different exceptions helpful which I have included here:


See slides for handling in controllers and rake tasks and notification using HopToad.

Monday, December 6, 2010

Truncate HTML in Rails

After a bit of searching for a truncation helper for HTML, I found this great gem: truncate_html. It maintains the HTML tags (i.e doesn't strip them out) and supports word boundaries. Nice! Oh, and supports Rails 2.x and 3.x.

Saturday, November 27, 2010

Recent Project: "Aldo's Let's Dance" Fall Campaign

By the lack of blog posts this month, you might have guessed that I've been busy. You're right! I even failed to blog about a launch early this month. But here it is...

I had a great time working with Dynamo, located in the old port of Montreal, on Aldo's fall campaign, "Let's Dance". The concept is simple: upload a video of yourself dancing to Think About Life's Sweet Sixteen and let Internet groupies vote via Twitter, Facebook and/or YouTube. The entries have been fantastic, the traffic through the roof, and voter participate off the charts. It's definitely the most fun I have had all year. Check out the screen shots below and some technical details for those inclined, but better yet visit the site before 6th December to get the full experience before voting ends.

Thanks to Alex (Interactive Director), Jenna (Senior Designer) and Marie (Front-end Integrator) from Dynamo who made this such an enjoyable project to work on.

Home Page

Aldo Let's Dance Home

Gallery

Aldo Let's Dance Gallery

Video

Aldo Let's Dance Video

Registration

Aldo Let's Dance Registration

Technical Details

"Let's Dance" is built using Ruby on Rails, tested with Cucumber and RSpec and deployed on Heroku. The application integrates several different services via Oauth: Twitter, Facebook and YouTube. By using Oauth we are able to track unique votes, as each vote is captured with the voters Oauth ID, but still allow visitors to share videos as many time as they wish.

Video uploads and approvals are managed using YouTube Direct and deployed on Google App Engine. While this saved development time, the open source application does not currently support Internationalization. It was possible to "hack" this in, but it was more time consuming than it should have been. Having said that, it was great to be able to off load all video processing and management to YouTube.

Deploying on Heroku is a huge help with the sudden influx of traffic. With campaign sites, there's no ramp up with traffic, so the application has to handle large amounts from day one. We monitor performance using NewRelic (on-demand application management), to ensure the application has the resources it needs for fast response times.

Need help with you Ruby on Rails application?

Please contact Nicholas Henry at Firsthand Web Design.

Thursday, October 28, 2010

CarrierWave, an alternative to PaperClip for Uploading Files in Rails or Ruby Applications

I recently switched to CarrierWave: "Classier solution for file uploads in Ruby for Rack, Rails, Merb and Sinatra". Why? Here's three reasons:

  1. Uploading logic/handling is extracted into a separate class. Hence the tag "Classier solution". It addresses my sensibility for Single Responsibility and separation of concerns.
  2. It maintains a cache across redisplays. Meaning the user does not need to upload a file again, if other fields are invalid on the model.
  3. Dead easy upload from a remote URL.

Definitley give it a try. Anything I have missed? Let me know in the comments.

Thursday, October 21, 2010

ActiveRecord::Base#becomes

An ActiveRecord method I did not existed: becomes.

Returns an instance of the specified klass with the attributes of the current record. This is mostly useful in relation to single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record identification in Action Pack to allow, say, Client < Company to do something like render :partial => @client.becomes(Company) to render that instance using the companies/company partial instead of clients/client. Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either instance will affect the other.

Web Integrator Application Hand-off Checklist

One scenario in developing applications, is the application is built and then handed off to a Web Integrator to implement the CSS. The other is templates are created and these are integrated by the web developer. This checklist is primary for the first scenario, but is probably applicable to the second. Here is a list of checks you should make before handing off for integration:

  • Demo data: Can the web integrator easily add demo data to the application. This should be done via a script.
  • Translation: If your application is multi-lingual, ensure all strings are in a locale file and the Web Integrator knows how to edit these. Spend some time teaching the Web Integrator on how it works.
  • Test translations: Before an application is translated, run the application in the secondary language to make sure that all "strings" for that language are missing. Check especially for emails static pages and built-in error messages, labels and attributes.
  • Language Switcher: Ensure a language switcher exists and is working.
  • Emails: If your application sends emails, ensure the developer can send and preview these easily. This can be done with the a script to send emails and a preview option via http. Rather than your application send emails, use a email service provider.
  • Minimize custom helpers: Helpers can be a roadblock for a Web Integrator not familiar with Rails. If you do use helpers, have the helper render a partial which can be easily customized.
  • Test accounts: Most applications are not standalone these days. If your application connects with external services such as Twitter and Youtube, ensure test accounts have been setup and can easily be used. You want to encourage the Web Integrator to use these integrations as much as possible. It's a great way to catch bugs!
  • Overlay option: Seen a web site without an overlay these days? Allow your Web Integrator to render a page without the entire layout easily. Passing a parameter along the URI is great way to do this.

Any thing I have missed? Please let me know in the comments.

Tuesday, October 19, 2010

Rails UJS using jQuery results in Unknown File Type/Prompted to save file with IE

I'm developing a Rails 2.3 project with the UJS file for Rails 3. Instead of the remote_form_fortags, I'm adding the data-remote attribute. This was running great on Safari and Firefox, but testing a form post on IE would result in the browser trying to save the file. There are a lot of posts regarding this issue, but none of them worked for me.

The fix ended up being very simple. Upgrade jQuery. The application was using 1.4.2. I upgraded to 1.4.3 and everything worked as it should under IE.

Related posts

Please note this blog is no longer maintained. Please visit CivilCode Inc - Custom Software Development.