19
Jul
09

Mock Cookies in Rails Tests the Easy Way

I got really tired of mocking out cookies every single time I made a reference to cookies in my test. It looked like a bunch of spaghetti code that made me mock out every single cookie call that I could imagine. Don’t get me wrong, I think mocks are wonderful, but when you have to mock out every single call, I don’t think the pain is worth the gain. I found it much easier to mock cookies like this as like this, which gives a pretty good approximation of rails cookies. It won’t work for 100% of cookie testing cases, but for 99.9%, it works like a charm.

I use rspec to test, but you could easily port the Cookie class to any testing framework that you want.

def stub_cookies
  stub!(:cookies).and_return(MockCookie.new)
end

class MockCookie < Hash

  def [](name)
    super(name.to_s)
  end
 
  def []=(key, options)
    if options.is_a?(Hash)
      options.symbolize_keys!
    else
      options = { :value => options }
    end
    super(key.to_s, options[:value])
   end

  def delete(key,opts)
    super(key)
  end

end

08
Jul
09

DRY Views in Rails with Blocks

I’m a fan of the DRY (Don’t Repeat Yourself) principal. I think that computers were invented for a reason and that reason was not so that I could do the same thing over and over. If it’s one thing that computers do well, it’s doing the exact same thing ad nauseum. So, I do as much as I can in order not to repeat myself a lot when coding.

I have an case now where within the main portion where content is rendered sometimes there separate content on the right side, and sometimes there is not. For example, with no content on the right side, it looks like so:

  <div id="left">
    I am left content
  </div>

Simple enough, but when there is content on the right side, the left side has to get a little smaller, so there is a class added called “with_left” to the left div that makes the width less to accommodate the right content.

  <div id="right">
    I am right content
  </div>
  <div id="left" class="with_right">
    I am left content
  </div>

The problem comes in when the right content is different from page to page and I’m not exactly sure if there is going to be any right content to begin with, as it relies on some dynamic data. Sure, I could do something like this for every page, but I would get annoying fast, and I’m sure there would be one instance where I would forget to do it the right way:

  <% if right_content %>
    <div id="right">
      <%= right_content %>
    </div>
  <% end %>
  <div id="left" <%= 'class="with_right"' if right_content -%>>
    I am left content
  </div>

So, in comes Ruby to the rescue. I heart blocks and I’m glad that ruby has them, because this is a great case where they come in handy. Instead of doing the above logic over and over again, I can create a method called main_content that allows me to do this in a more generic way.

  def main_content(params={},&amp;block)
    right_content = params[:right_content]
    unless right_content.blank?
      right_div = <<-HTML
        <div id="right">
          #{right_content}
        </div>
      HTML
      concat(right_div)
      concat('<div id="left" class="with_right">')
    else
      concat('<div id="left">')
    end
    yield
    concat('</div>')
  end

Now I can use this method like so:


  <% main_content(:right_content=>render(:partial=>'account_actions')) do %>
    <h3>Edit Account</h3>
  <% end >%

If the partial account_actions renders anything, I will get this:

  <div id="right">
    Output of account_actions partial
  </div>
  <div id="left" class="with_right">
    <h3>Edit Account</h3>
  </div>

If the account_actions partial doesn’t end up rendering anything, then I get:

  <div>
    <h3>Edit Account</h3>
  </div>

Nice! Everything looks good, so I can start adding some tests to it. Here’s how I tested it with rspec:

  describe 'main content renderer' do
    
    before do
      @buffer = ""
      stub!(:output_buffer).and_return(@buffer)
    end
    
    it 'will render only the left div when there is no right content' do
      main_content{}
      output_buffer.should have_tag("div#left")
    end
    
    it 'will put the yielded content in the left div' do
      main_content{concat("Yielded content")}
      output_buffer.should have_tag("div#left","Yielded content")
    end
    
    it 'will display the right content in the right div if there is any' do
      main_content(:right_content=&gt;'Right'){}
      output_buffer.should have_tag("div#right","Right")
    end
    
    it 'will add a class of "with_right" to the left div if there is right content' do
      main_content(:right_content=&gt;'Right'){}
      output_buffer.should have_tag("div#left.with_right")
    end
    
  end

07
Jul
09

Twitter as a non-profit?

Let me first say that I don’t use Twitter. I see why people like it and I see why it is popular. I’m not one of those curmudgeons who bemoans its use, I just have enough things to keep up with. Someday, I’ll hope on the proverbial bandwagon.

Even though I don’t use it, it’s hard to do much anymore without hearing about it. Whenever there is a news event now, it seems like people are tweeting about it or the source came from a tweet (ala Jeff Goldblum’s non-death).

So, yes, Twitter is popular. And everyone has been speculating on how Twitter is going to make money, because as of now, they are surviving on VC dollars and the hope of making money down the road. A quick search on google will give you an idea as to how people have tried to make their own revenue model for Twitter.

Most of these models rely on some sort of ad delivery system, which is a pretty standard way to make dough. However, given the large number of people who use Twitter indirectly via the API, most ads within the page will not be seen by the users. That leaves you with putting ads in the tweets themselves, which will probably do nothing but make users feel as if their privacy has been invaded by a door-to-door salesman who just happened to show up in their Twitter feed.

So, I say let’s make Twitter a non-profit, much in the way that Wikipedia works. Just like Wikipedia, Twitter has totally user generated content. Also, they are both excellent data sources in their own way. Wikipedia for more historical data, Twitter for more transient and current opinions.

I think with a large passionate user base like Twitter, raising funds to keep it going would not be too hard. I also think it would allow them to keep developing a platform that is good for the community at large instead of business stakeholders who want a return on their money. Twitter is a good platform and I’d hate to see them go down because of a lack of monetary plan or, even worse, because it alienates its users by pumping in ads where they are not wanted.

Let’s get those dollar signs out of your eyes and do something reasonable. So, Twitter Foundation, anyone?

17
Jun
09

Super Easy Tabs in Rails

All the cool kids these days seem to be doing navigation via tabs, and since I want to be cool, too, I figured I might as well do it to. Ya, sure, there are plenty of plugins out there that do this, but it always seems like these things have too much configuration and code for its own good.

So, I went at it on my own and, really, if the tabs are simple, the solution is pretty simple. My tabs are based on the controller name, which means the current tab maps to all the actions of a certain controller. In other words, it’s kind of the way Basecamp does it.

First, let’s start with some code in the controller. In my app, everything that uses tabs is inherited from a base controller called LoginProtectedController. That’s where I put this code, but it would work just as well in the ApplicationController:

  helper_method :current_tab

  def self.current_tab(tab_name)
    before_filter do |controller|
      controller.send(:current_tab=,tab_name)
    end
  end

  protected

  def current_tab=(tab_name)
    @current_tab = tab_name
  end

  def current_tab
    @current_tab || controller_name.titleize
  end

So, this is what I have in one of my controllers to mark that the tab is not the name of the controller, but called ‘Dashboard’

  current_tab 'Dashboard'

Now for some helper code for displaying the tabs:

  def tab_link(args={})
    html_options = {}
    html_options = {:class=>'current'} if args[:tab] == current_tab
    link_to args[:tab], args[:path], html_options
  end

And here’s how you put it together in the view:

<div id="navigation">
  <%= tab_link("Dashboard", :path=>admin_path) %>
  <%= tab_link("Items", :path=>admin_items_path) %>
  <%= tab_link("Users", :path=>admin_users_path) %>
  <%= tab_link("Account", :path=>edit_admin_account_path) %>
</div>

If you want to make it look all pretty, some CSS should spruce it up:

#navigation {
  line-height: 100%;
  margin-left: 6px;
  float: left;
  font-size: 12px;
}

#navigation a {
  background-color: #CCCCCC;
  color: #000000;
  padding: 7px 15px;
  text-decoration: none;
  display: block;
  float: left;
  margin-left: 2px;
}

#navigation a:hover {
  background-color: #BBBBBB;
}

#navigation a.current, #navigation a.current:hover {
  background-color: #FFFFFF;
}

03
Jun
09

Proper DRM

The wife and I are planning a summer vacation to the northern parts of Japan, so instead of buying the whole guidebook for Japan, which runs at 35 bucks, we decided to buy the one chapter that we will actually use. This is a new idea by Lonely Planet and I think a great one, especially considering how much of the actual guide book people use when traveling. So, we went to their website, chose the chapter, and downloaded the PDF we were looking for. I almost assumed that there was some sort of DRM applied that would not let me print it or open it on another computer. However, I was wrong in this case. The text at the bottom of the PDF explains it all:

To make it easier for you to use, access to this chapter is not digitally restricted. In return, we think it’s fair to ask you to use it for personal, non-commercial purposes only. In other words, please don’t upload this chapter to a peer-to-peer site, mass email it to everyone you know, or resell it. See the terms and conditions on our site for a longer way of saying the above – ‘Do the right thing with our content.’

To which I say, good for them. There are too many instances of companies being super guarded with their content that they attach some sort of restrictions to what one can do with the content. And the reality is, if someone really wants to do something, they probably will. There are ways to get around just about any DRM protected file if you want and by locking it down, you are basically insulting your customers and telling them “I don’t trust you”.

Instead of not trusting their users, they’ve basically said “Listen, we know you can take this and give it to anyone you want. But, we trust that you won’t do that. Thanks!” And you know what? I won’t. I’ll keep it to myself and use it as if it were a real book.

I think it’s something to think about for all the software out there that has ridiculous pricing models based on the number of CPUs or users, etc or music download sites that restrict how the music you downloaded can be shared.   Make it easy for the customer and the customer will reward the company with loyalty and more revenue. Bog the customer down with restrictions and force him to spend more money upfront will lose future loyalty.

28
May
09

How Not to Code With Javascript

I’ve had quite a frustrating day today trying to get my internet hooked up here in Korea.  To finalize the connection here, you must register your computer with the company via their website.  Or, at least, that’s what I’m assuming as the site is in Korean and the guy installing the internet didn’t speak much English.

Anyway, the registration site wasn’t working because when the installer dude was clicking on the menu tabs, nothing was happening.  I pulled the same site up in Safari and FF3, but still, it didn’t work.  Being ultra annoyed at this point, I opened Firebug and started going through the code.  Here’s what the menu tab link looked like:

    <a href="javascript:goMenu(1)"</a>

And the offending javascript:

    function goMenu(menu)  {
        
        if(menu == 1)
            location.href = "/sw5/order/wm/wm_install.jsp";
        else if(menu == 2)
            location.href = "/sw5/order/wm/wm_repair.jsp";
        else if(menu == 3)
            location.href = "/sw5/order/board/board/supportBoardList.jsp";
        else if(menu == 4)
            location.href = "/sw5/order/board/bbsDown/supportFileList.jsp";
        else if(menu == 5)
            location.href = "/sw5/order/board/bbsError/supportErrorList.jsp";
        }

Technically, there’s nothing wrong with the javascript. It should work fine, but since there were some errors in some of the other javascript, the whole javascript file didn’t parse correctly, therefore, this particular function didn’t make its way to the javascript interpreter in the browser (unless your browser was IE7 for some reason).

The bigger question of course is why would you ever program like this? Does the person who wrote this have no idea what an anchor tag does? Why would he/she not choose to just put the URL into the href of the anchor tag? I mean, this is pretty fundamental here. If you ask anyone who’s even attempted to make a website for more than a day, I’m sure they could tell you how to make an anchor tag. On top of that, a it would be better to at least explicitly use the window object and call window.location.href. But I guess, if you don’t know how an anchor tag works, why bother with doing javascript correctly.

So, curious as to what else the programmers of this site could possibly do, I saw two methods defined that looked kind of funny that are probably the reason the javascript file wasn’t interpreted correctly.

    function document.oncontextmenu() {....}
    function window.onload() {....}

So, the programmer isn’t trying to call the document.oncontextmenu or window.onload functions, the programmer is trying to define these functions. I can’t really fathom why you would ever, ever want to do this. Of course, most normal javascript parsers think that you are calling the function window.onload instead of defining a method called ‘window.onload()’, so the javascript bombs out. I guess the IE parser is a little more lenient and probably silently ignores it. But again, it just baffles my why anyone would write this and that code like this made it to the registration site of one of the largest internet providers in Korea, which happens to be the most wired country in the world.

How are we teaching people to make websites these days, anyway?

27
May
09

It’s a Poor Craftsman Who Blames His Tools

I don’t understand a lot of the arguments that pit one framework or language against another.  Ok, I understand them in the technical sence, but I don’t understand why people seem to like to argue about them a lot.  Given the proliferation of blogs about how language X or framework Y is way better than some other “competing” language/framework, either the writers are just using cheap ploys to get people to read their blog or there are more people out there like the Comic Book Guy from the Simpsons than I think.

Worst.  Framework.  Ever.

Worst. Framework. Ever.

Case in point is this post: Java Kicks Ruby on Rails in the Butt.  Not only is the article riddled with assumptions, it compares a framework (Ruby on Rails) with a language (Java).  Talk about an apples-to-oranges comparison.  Basically, it creates an application in Rails with the scaffolding and says “look, it’s not very cool looking”, then uses some Java open source tools to build the same application.  Clearly, the screen is prettier, so the Java one is much cooler and easier.  There’s no mention that, yes, you can actually have both and run Ruby on Rails in JRuby in your JVM, but let’s not mention that.

Another misguided post can be found here: Ruby on Rails and the Importance of Being Stupid.  For the lazy, like me, let me summarize this one for you: site A was written in ASP.NET and runs super well but site B was written in Ruby on Rails and takes 5 minutes to load a page.  Despite the fact that site A and site B are completely different sites written by different people for different reasons, the author feels compelled to go ahead and compare the 2 anyway.  He is actually kind enough to to mention all of the design flaws with the RoR site, most of them having to do with a so-called “MIT Genius” who over-engineered a solution and who apparently doesn’t have the first incling of how RoR’s ActiveRecord works.  Overall, he seems to be making the point that this one “MIT Genius” fellow made a bad site with RoR and he is stupid, therefore Ruby and RoR is stupid.  He comes off as a bit of a curmudgeon, pissing on anything new, instead of just admitting that the “MIT Genius” guy made some mistakes.  Was it RoR or Ruby’s fault?  No, it was a case of someone who didn’t know how to use his tools well.

Which brings me to the point.  There is nothing inherantly wrong with Ruby, Java, PHP, Lisp, ASP.NET, or any other framework/language that you can think of.  They are all just a tool to get the job done.  If you use that tool like an idiot, then, well, who’s to blame: you or the tool?  There’s an old proverb that says:

It’s a poor craftsman who blames his tools.

Which is exactly the problem.  Listen, if your given a hammer and you use the handle end to try to put a nail into a piece of wood, it’s not the hammer’s fault.  It’s your fault.  You. I’ve seen whole houses in Central America being made with just machetes.  Seriously, people will use them to hammer, cut, turn screws, and just about anything else you can think of.  They have one tool, they know it well and they build pretty sturdy homesteads with this simple instrument.

Machete: More uses than a Swiss Army Knife

Machete: More uses than a Swiss Army Knife

You can make a perfectly good website using Perl and SSI for all I care.  It gets the job done.  Or you can even go further and create static HTML files and FTP them to a web server.  Whatever suits you.  All the end user cares is that it works.

Personally, I like Ruby and Ruby on Rails.  It makes me happy to develop with it.  If you like something else, go ahead and use it, no sweat off my back.  Just quit complaining about the tools I use and learn how to use yours properly.

30
Apr
09

Time for Rails to Grow Up

So, I’ve been particularly absent in my internet time as I’ve moved from Argentina, then the States, then Korea all in the past 3 months. In other words, it’s been a bit hectic lately.

And what do I see when I come back? It’s an argument over a presentation that someone did at the Golden Gate Ruby Conference called “CouchDB: Perform like a pr0n star”. You can see the slides at the end of this blog.  There has been much debate on it, as seen here, here, and here (and probably at many other sites, too).  During the whole thing some people say “so what” while others say it’s a disgrace while DHH and many of the core developers as I understand it have actually embraced it, theorizing that edgy is good.  This actually casued one of the ruby activists,

13
Feb
09

Doing an Include on Class in Ruby Just Confuses the Hell Out of People

So, I was updating someone else’s project at github and noticed that the author did this:


module ModuleName

  def foo
    "I am foo!"
  end

end

Class.send :include ModuleName

Ok, that’s fine. Looking at that you would think that the methods in ModuleName would be added as instance methods to class, which is true, but that doesn’t mean it does what you think it does.

When doing the above, the module methods end up being class methods on any class that you have. What? Yes. It is because in Ruby, everything is an object. Even classes. So, when you have a class in Ruby, it is actually a singleton object. When you create instances of classes, it again is an object, but it’s not a singleton and it’s not designated as a class.

So, when this code runs, you are adding methods to the singleton objects of every class, which look like class methods to any object that you create.


class SomeClass

  def instance_foo
    "I am instance foo!"
  end

end

SomeClass.foo  // will return "I am foo"
SomeClass.new.instance_foo // will return "I am instance_foo

Ok, so the Class.include thing is totally legal and fine, it’s just confusing and would be more clear if it was done like so.


module ModuleName

  def self.included(base)
      base.extend(ClassMethods)
    end

  module ClassMethods
  
    def foo
      "I am foo!"
    end

  end

end

Object.send :include ModuleName

Sure, it’s a semantic difference, but it’s just a little easier to read and understand what’s going on.

03
Feb
09

Getting The MySQL Ruby Gem to Work With Mac: Hit the Reset Button

.If you do a search right now on google for “mysql gem mac” you will find 999 blogs about the solution to this (numero 1000 being this one), but unfortunately, NONE of these worked for me.  Thanks a lot, Google!  I thought you were smart!

Ok, ok, to be fair it kind of worked. The gem would install, but then I would get this error message when trying to start Rails:

Failed to lookup Init function /usr/local/lib/ruby/gems/1.8/gems/mysql-2.7/lib/mysql.bundle

Right. That’s when I decided to just hit the reset button and re-install MySQL.

Basically, I had MySQL5 running on Mac OSX 10.4.11 with ruby and rails and the works.  Then I took off for a one-year-long sabbatical, came back, and now the world of Rails has changed a bit.  Most glaringly in the beginning is that the MySQL libraries are no longer included in Rails since 2.2.  This is probably a good thing as the MySQL libraries that were included were notoriously slow and it was always recommended to use the gem instead.  I didn’t on my local machine before because since I am the only one using it, I could care less about performance.  However, I’m sure there was someone out there (or many) who used the default MySQL libraries shipped with Rails in production or for some kind of performance test, complained about it, until finally the Rails core team decided to just rip it out.  Anyway, good for Rails, bad for me.

To make a long story short, I spent hours trying all the tips out there to get the MySQL gem installed, including modifying the make file which I haven’t done since some absurd class I took in college.  So, I did what any reasonable person would do: uninstall mysql and re-installing it with mac ports.  For some history, MySQL before was installled from the binary package that can be downloaded from their site.

In any case, if you want to do this on your computer and keep any data in your database, you should use the mysqladmin tool to dump it out into a file for re-import later on.  If not, your choice.

mysqldump -u root -p --all-databases > mysql-dump.sql

Anyway, to uninstall MySQL, I did the following in a terminal window (props to this post):

sudo rm /usr/local/mysql
sudo rm -rf /usr/local/mysql*
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*
edit /etc/hostconfig and remove the line MYSQLCOM=-YES-
sudo rm -rf /Library/Receipts/mysql*
sudo rm -rf /Library/Receipts/MySQL

Then I used macports to install MySQL5:

sudo port install mysql5 +server

That should take a little while. After it’s done, I created the initial MySQL databases. Notice that the command is mysql_install_db5 instead of mysql_install_db. This is a macports thing. All of the executables that I can tell have 5 appended to them (i.e. mysql5 instead of mysql). This shouldn’t be too much of a problem if you can remember it.

sudo -u mysql mysql_install_db5

If you want to start up the server now, you can and check that it’s running.

sudo /opt/local/lib/mysql5/bin/mysqld_safe &
ps aux | grep mysql

Or, if you’re lazy, like me, you can also have it start up when the computer starts:

sudo launchctl load -w /Library/LaunchDaemons/org.macports.mysql5.plist

Another lazy move is to symlink the socket file to where all programs look for it. I didn’t want to specify this every time, so I just symlinked it to where most apps look for it:

sudo ln -s /opt/local/var/run/mysql5/mysqld.sock /tmp/mysql.sock

And if you want to right now, go ahead and set a password for the root MySQL user.

mysqladmin5 -u root password [your_password]

If you backed up your data, now is a good time to restore it:

mysql5 -u root -p < mysql-dump.sql

Finally, installing the gem is a breeze:

sudo gem install mysql -- --with-mysql-config=/opt/local/bin/mysql_config5

Done! Woohoo!




Stay Updated

or

Get new posts via email

Software Blogs - BlogCatalog Blog Directory

 

January 2012
M T W T F S S
« Jul    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Follow

Get every new post delivered to your Inbox.