I was going into a project to do some general code refactoring (it’s a hobby you know), and found some tests that were failing. Figured I’d fix those first and then whine to whoever left failing tests in a project later. One test failure in particular looked a bit odd to me:
1) Error: test: The 'Add to Web' form should pass a URL into the form. (LettucesControllerTest): ActionView::TemplateError: undefined method `rewrite' for "http://mocked.com":String On line #1 of layouts/\_footer.html.erb 1: <%= link_to 'Privacy Policy', privacy_policy_path %> 2: <%= link_to 'Terms & Conditions', terms_path %> 3: <%= link_to 'Contact Us', site_contact_path %> (eval):15 app/views/layouts/\_footer.html.erb:1
…that’s interesting, I thought. What does http://mocked.com
have to do with
anything in that line? Well the functional test looked like this:
setup do
login_as :activated_user
get :new, :url => 'http://mocked.com'
end
…and the action in the controller looked like this:
# User added lettuces page
# scrapes lettuce URL if given for suggested title and images
def new
@url = params[:url]
@lettuce = @url.blank? ? Lettuce.new : Lettuce.from_url(@url)
end
Ok, it looks like an external site can pass a url
param in via the url, to
indicate which page this action should reach out to and scrape for Lettuce
content. I removed the @url
assignment line from the action and put a <%=h
@url.class %>
and and <%=h @url.methods.sort %>
into the new
view file and
loaded that in my browser.
Sure enough, @url
is an ActionController::UrlRewriter
, and it has a
#rewrite
method, amongst some other things. I’m guessing that Rails routing is
using this somewhere, but I’m not curious to go find out because it will delay
my refactoring mission.
Now, thankfully I didn’t like that there was an instance variable named @url
in the first place, since it was being created only for the purpose of letting
the view use an instance variable instead of accessing #params
directly.
However, there was a conditional case in the view for how to handle a #blank?
url vs a non blank url, so it had to be available to the view somehow. I
refactored to:
def new
@lettuce = requested_lettuce_url.blank? ? Lettuce.new : Lettuce.from_url(requested_lettuce_url)
end
protected
helper_method :requested_lettuce_url
def requested_lettuce_url
params[:url] || ''
end
And now:
- The functional tests all pass.
@url
does not get overwritten, so the routing code will now work.- The view has access to a
#requested_lettuce_url
method (a bit verbose, but#lettuce_url
collides with a named route). - The incoming param stays the same, so any external pages which linked to this
import lettuce
view won’t have to change how they link to the page.
Now that the lettuces_controller
is looking good, I can start working on the
meats_controller
and see what it has in store.