Skip to content

Commit

Permalink
Markdown has won the format war, sorry Textile.
Browse files Browse the repository at this point in the history
  • Loading branch information
jqr committed Mar 3, 2016
1 parent 5fc2afd commit 423c2d9
Show file tree
Hide file tree
Showing 15 changed files with 112 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ Rails has this handy method that allows you store almost any object in the datab

Here is the proper syntax for telling Rails that there is an options attribute that should only store Hash values.

{% highlight ruby %}
```ruby
class User < ActiveRecord::Base
serialize :options, Hash
end
{% endhighlight %}
```

<h3>The problem</h3>

The options attribute will start off as nil, and remain nil until you set it to something else. Setting the class_name to Hash only affects what you can write to this attribute.

{% highlight irb %}
```ruby
>> user = User.new
=> #<User id: nil, name: nil, options: nil>
>> user.options[:theme]
Expand All @@ -27,41 +27,41 @@ You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]
from (irb):2
=> nil
{% endhighlight %}
```
<h3>The solution</h3>
What we really need is to automatically return an empty Hash on this new object so we can go on our merry way.
Add this to your environment.rb.
{% highlight ruby %}
```ruby
config.gem 'jqr-typed_serialize',
:lib => 'typed_serialize',
:source => 'http://gems.github.com'
{% endhighlight %}
```
Now run this command to install the gem.
{% highlight sh %}
```sh
$ rake gems:install
{% endhighlight %}
```
A quick change of our model will fix all of our woes.
{% highlight ruby %}
```ruby
class User < ActiveRecord::Base
typed_serialize :options, Hash
end
{% endhighlight %}
```
{% highlight irb %}
```ruby
>> user = User.new
=> #<User id: nil, name: nil, options: nil>
>> user.options[:theme]
=> nil
>> user.options
=> {}
{% endhighlight %}
```
Voila!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ summary: The design process of a Rails pattern.

My <a href="http://github.com/jqr/typed_serialize">typed_serialize plugin</a> came from the repetition of code just like this.

{% highlight ruby %}
```ruby
serialize :options, Hash

def options
Expand All @@ -17,7 +17,7 @@ def options
self.options = {}
end
end
{% endhighlight %}
```

It calls super to peek at what ActiveRecord would return for the serialized column. If it's a Hash, we just return it right away. If it's anything else we set it to a new Hash and return that.

Expand All @@ -26,11 +26,11 @@ It calls super to peek at what ActiveRecord would return for the serialized colu

After thinking about the pattern for a bit, I decided that simplest shorthand would be this.

{% highlight ruby %}
```ruby
class User < ActiveRecord::Base
typed_serialize :options, Hash
end
{% endhighlight %}
```

This code says "there is a typed and serialized attribute named options, that will always be a Hash." Notice that it is nearly the same usage as the original serialize method.

Expand All @@ -39,38 +39,38 @@ This code says "there is a typed and serialized attribute named options, that wi

First off, we define a method that is accessible at the time of class definition. Since the usage is the same as serialize, we can use the original serialize method definition as a starting point.

{% highlight ruby %}
```ruby
class ActiveRecord::Base
def self.typed_serialize(attr_name, class_name = Object)
end
end
{% endhighlight %}
```

On second thought, what's the point of class_name being optional? It made sense for the original serialize method, but not typed_serialize. Let's make class_name mandatory.

{% highlight ruby %}
```ruby
class ActiveRecord::Base
def self.typed_serialize(attr_name, class_name)
end
end
{% endhighlight %}
```


OK, now our User model can properly execute, but it does absolutely nothing. So let's at least call Rails' serialize method to get the standard behavior.

{% highlight ruby %}
```ruby
class ActiveRecord::Base
def self.typed_serialize(attr_name, class_name = Object)
serialize(attr_name, class_name)
end
end
{% endhighlight %}
```

<h3>Adding the meat</h3>

Our repeated code revolved around a custom reader for a serialized attribute. So let's add a custom reader for attr_name using define_method and our original repeated code.

{% highlight ruby %}
```ruby
class ActiveRecord::Base
def self.typed_serialize(attr_name, class_name = Object)
serialize(attr_name, class_name)
Expand All @@ -85,25 +85,25 @@ class ActiveRecord::Base
end
end
end
{% endhighlight %}
```

The original code has a couple of small problems when inserted into this context. It assumes the value should always be a Hash and written attribute is always named options.

A quick look at serialize's implementation tells us it stores its data in a hash with the key as the attribute name in string form, and the value is the class_name. We'll use that to derive the expected class.

{% highlight ruby %}
```ruby
expected_class = self.class.serialized_attributes[attr_name.to_s]
{% endhighlight %}
```

We'll use Ruby's send method to call a method with a name we won't know until runtime.

{% highlight ruby %}
```ruby
send("#{attr_name}=", expected_class.new)
{% endhighlight %}
```

<h3>All together now.</h3>

{% highlight ruby %}
```ruby
class ActiveRecord::Base
def self.typed_serialize(attr_name, class_name = Object)
serialize(attr_name, class_name)
Expand All @@ -120,6 +120,6 @@ class ActiveRecord::Base
end
end
end
{% endhighlight %}
```

This is my first post detailing an implementation. Interestingly enough, it alerted me to a few unnecessarily complex portions of even this tiny amount of code.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ Every time I setup a new git project, I end up adding .DS_Store to the .gitignor

Git supports global ignores just like any good SCM.

{% highlight sh %}
```sh
$ git config --global core.excludesfile ~/.gitignore
$ printf ".DS_Store\nThumbs.db\n" >> ~/.gitignore
{% endhighlight %}
```


For good measure I threw in Windows' creepy file <a href="http://en.wikipedia.org/wiki/Thumbs.db">Thumbs.db</a>.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ Pretty sweet right? Let's get started.

<h3>Install RSpec bundle</h3>

{% highlight sh %}
```sh
mkdir -p ~/Library/Application\ Support/TextMate/Bundles/
cd ~/Library/Application\ Support/TextMate/Bundles/
git clone git://github.com/dchelimsky/rspec-tmbundle.git RSpec.tmbundle
osascript -e 'tell app "TextMate" to reload bundles'
{% endhighlight %}
```

<h3>And now the fun begins</h3>

Expand Down Expand Up @@ -72,10 +72,10 @@ Who has time to rename all those files? Definitely not you!
There is also a <a href="http://github.com/jqr/thor_tasks/raw/master/rspec_rename_to_dotspec.thor">fancy converter</a> for renaming all of your old specs!


{% highlight sh %}
```sh
# in your project dir
gem install thor &&
thor install \
http://github.com/jqr/thor_tasks/raw/master/rspec_rename_to_dotspec.thor &&
thor rspec:rename_to_dotspec
{% endhighlight %}
```
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ I've run into this situation a few times, most recently while adding some automa

First we subclass an exception and add an accessor for the data we'd like to pass and add it to the initialize method for easy construction.

{% highlight ruby %}
```ruby
class MyException < StandardError
attr_accessor :object

Expand All @@ -19,17 +19,17 @@ class MyException < StandardError
self.object = object
end
end
{% endhighlight %}
```

The only other important bit is how you raise this new exception.

{% highlight ruby %}
```ruby
raise MyException.new("Too Lazy", object)
{% endhighlight %}
```

h3. A realistic example
### A realistic example

{% highlight ruby %}
```ruby
class CacheError < StandardError
attr_accessor :object

Expand Down Expand Up @@ -61,4 +61,4 @@ rescue CacheError => err
err.object.expire_cache
retry
end
{% endhighlight %}
```
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ layout: post

I just discovered something interesting about Ruby's exception rescuing. Check out these two example methods that differ only by exception assignment.

{% highlight ruby %}
```ruby
def return_nil_on_error
begin
yield
Expand All @@ -23,13 +23,13 @@ end

puts return_nil_on_error { raise "error!" }.inspect
puts return_exception_on_error { raise "error!" }.inspect
{% endhighlight %}
```

Running the code above and this is what you will see.

{% highlight ruby %}
```ruby
nil
#<RuntimeError: error!>
{% endhighlight %}
```

It's interesting to see that Ruby treats the a rescue block as a value expression if it assigns the exception to a variable. Is there a valid use for this oddity?
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ layout: post

When you absolutely need to traverse a large number of objects in a table and have the ActiveRecord instance available, Rails now has a Model.find_each method that makes this safe and easy.

{% highlight ruby %}
```ruby
User.find_each(:conditions => ['last_login_at < ?', 30.days.ago]) do |user|
# ...
end
{% endhighlight %}
```

This feature has been available for a while through the use of a few <a href="http://github.com/guillermo/active_record_each">plugins</a> and <a href="http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord">snippets</a> floating around, but as of Rails 2.3 ActiveRecord::Base#find_each is now in Rails core.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ Most of the time a backtrace can help you zero in on a bug in your code quickly,

You could throw in some statements to print out certain variables to "see" what your code "sees" at that point in time, but there is a far easier way.

h3. Your friend: debugger
### Your friend: debugger

The excellent ruby-debug gem lets you open up an instance of irb wherever you put a call to debugger. If you haven't already, check out the excellent <a href="http://pivotallabs.com/users/chad/blog/articles/366-ruby-debug-in-30-seconds-we-don-t-need-no-stinkin-gui-">30 second guide to ruby-debug</a>. Just type in "irb" when the debugger triggers to get a live irb session with the current state.

Normally this is more than enough to fix the problematic data/code. Today though I was iterating through a rather large set of data for importing from CSV. The problem data was something like 5 minutes into the import. I needed to open the debugger at the instant of the problem data and not on the thousands of rows of good data that preceded it.

h3. Start on a dime
### Start on a dime

A light when off in my head after a few minutes of stumbling around in console. Why not just wrap the offending bit of code in a rescue block and only open the debugger at that instant? I give you Instant Debug.

{% highlight ruby %}
```ruby
rows.each do |row|
begin
Item.create!(row)
Expand All @@ -27,7 +27,7 @@ rows.each do |row|
1 # no-op so the debugger can land in this context
end
end
{% endhighlight %}
```

Now if this code fails for any reason, we can see the exact state of the application that caused this problem. We are able to reproduce the issue easily by calling Item.create!(row) and we can even modify row to see if we can fix bad data.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ <h3>Start the clock</h3>

<p>First timer? You'll need to do some minor setup. The middle command will ask you for your Heroku login/password and upload your SSH pubkey.</p>

{% highlight sh %}
```sh
sudo gem install heroku
heroku keys:add
heroku create
{% endhighlight %}
```

<p>Heroku installs gem dependencies for your app when you do a git push, so it needs to have a .gems file in an easy to parse format.</p>

<p>Run these commands to install a rake task for automatically generating a .gems file from your Rails gem dependencies. You'll need to rerun the rake task whenever you change your dependencies.</p>

{% highlight sh %}
```sh
curl http://gist.github.com/101101.txt > lib/tasks/heroku.rake
rake heroku:gems
git add lib/tasks/heroku.rake .gems
git commit lib/tasks/heroku.rake .gems -m "Adding gem manifest for Heroku."
{% endhighlight %}
```

<p>Here we go, push your app, migrate the database and open it in a web browser! </p>

{% highlight sh %}
```sh
git push heroku master
heroku rake db:migrate
heroku open
{% endhighlight %}
```

<h3>Done</h3>
<p>Your application is up and running on Heroku's servers, 100% ready to use. Check out the next guide on setting up <a href="/2009/04/25/deploying-multiple-environments-on-heroku.html">multiple environments with Heroku</a>.</p>
Expand All @@ -44,7 +44,7 @@ <h3>Troubleshooting</h3>

<p>If the application had any trouble starting try the commands below to get a better view.</p>

{% highlight sh %}
```sh
heroku logs # view the application logs
heroku open # some error messages show on the web
{% endhighlight %}
```
Loading

0 comments on commit 423c2d9

Please sign in to comment.