December 29, 2009

Magnetism as an integrated system or independent?

Before I get started, I haven’t gotten to Liquid filters like I had planned. Thats still on the way. Instead, I’ve been banging my head to decide what is the best approach to take for the administration portion of a blog/CMS.

Integrated System

When I say an “integrated system” I mean a system that lays on top of the existing site, a toolbar. This is a very basic wireframe of the concept.

This approach can be very friendly because it’s your site, but with tools. The website and the admin panel are mixed. If I continue down this road the website has to be built in order for the admin panel to be accessible. Data can’t be entered into a site that isn’t built. Going this route also means the developer has to be CSS conscious. Using !important in CSS would be at the top of my list of “No-Noes.” These are two large issues I see with this kind of system.

Independent System

An independent system would exist completely separate from the website. The views would not mix. This creates a major disconnect from the content entered and the design of the website. On the brighter side, that disconnect removes the need of building the website first and potentially conflicting CSS. I think I’ll continue with this approach.

Now I need to layout the dashboard page, the first page you see after logging in. Before I start pretending to be a designer I need to figure out what I need and what I want to appear on this dashboard. Once I login I want to be one click away from entering new content. The content I’m entering could be a blog post, a conversation, a quote, an image or video or a code gist for the programmers out there. I will also want to see whats been happening with my site. Have content entries been added, modified or commented on? This is information I’d like to see.

Those are some ideas. It’s time to get started on the sketches. More on that as it comes.

December 07, 2009

It has Liquid::Blocks and it's called Magnetism

In my previous post about Liquid I never gave my project a name. Today it’s called Magnetism. It’s a pretty cool name for something that doesn’t work yet. I’ll be writing about Liquid assuming the audience is aware of what it and the Liquid syntax. Liquid consists of a few pieces. There are filters, drops, tags and blocks. This post will be going over blocks. Future posts will go over the other elements of Liquid as I add them to the Magnetism project.

What is a Liquid::Block

Liquid comes with a few blocks by default. You have if, unless and for to name a few. These wrap around template content.

1
2
3
4
5
6
7
8
9
10
11
12
<!-- the if block -->

{% if this_case %}
  do something in here.
{% endif %}

<!-- the for block -->
<ul>
{% for element in elements %}
  <li>{{ element }}</li>
{% endfor %}
</ul>

The prepackaged blocks are essential for template development, but I needed a few more so I dug through the Liquid documentation and the source code and got my hands dirty. I store my blocks in RAILS_ROOT/lib/magnetism/liquid and register them in RAILS_ROOT/config/initializers/magnetism.rb, but more on that later.

I’ve packaged my blocks in Magnetism::Liquid, but this isn’t necessary. This is how both cases would look.

1
2
3
4
5
6
7
8
9
10
11
12
13
# packaged
module Magnetism
  module Liquid
    class HTML < ::Liquid::Block
      # ...
    end
  end
end

# not packaged
class HTML < Liquid::Block
  # ...
end

The difference is at the line of inheritance. In my packaged class Liquid::Block is prefixed with ::, but that isn’t necessary in the second example because the class is not packaged. When creating a Liquid block two methods are called. There is the initialize method and render. At the moment I only needed render.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# lib/magnetism/liquid/html.rb
module Magnetism
  module Liquid
    class HTML < ::Liquid::Block
      def render(context)
        return <<-EOF
<!DOCTYPE HTML>
<html>
#{super}
</html>
        EOF
      end
    end
  end
end

The render method always has Liquid::Context passed into it. Even though I’m not using context in my render method I still needed to define it so render wouldn’t error. Within render the super method returns any code contained in your custom block.

1
2
3
4
5
6
<!-- index.liquid -->
{% html %}
<body>
  <h1>My Liquid Template</h1>
</body>
{% endhtml %}

This isn’t all Liquid blocks can do, but that’s all I’ve needed for Magnetism thus far. I’ll revisit Liquid blocks and explain Liquid::Context when I work on the comments form. Stay tuned for more!

December 05, 2009

Rendering Liquid templates from outside the views directory

Today I’m working with Liquid in Rails. I’m setting up a theme system for this project so I decided to store the liquid templates in RAILS_ROOT/app/themes. With all of that said, lets start from the beginning.

First add the Liquid gem to the environements.rb file.

1
2
# RAILS_ROOT/config/environments.rb
config.gem "tobi-liquid", :lib => "liquid", :version => ">= 2.0.1", :source => "https://gems.github.com"

Next unpack the gem with: rake gems:unpack. That will add the gem to vendor/gems. At this point you can render liquid templates within the app/views directory, but not outside of the views. You can test this by creating some controller and replacing the view’s .html.erb extension with .liquid and tell the controller to render the liquid template: render "your_file.liquid"

I’d like to render liquid templates that exist in app/themes so I did the following: render "#{RAILS_ROOT}/app/themes/default/templates/index.liquid" Instead of rendering the template like I expected, my browser downloaded the unprocessed liquid file. This is all handled with ActionView. I don’t know why ActionView will only render liquid templates within the app/views directory, but it will render regular .erb files from anywhere.

The solution was very simple after looking over the Liquid’s LiquidView documentation. I just had to tell ActionView to handle liquid files with LiquidView! This documentation is just old enough to not work anymore. ActionView::Base::register_template_handler was available at that location until version 2.1. It is now ActionView::Template.register_template_handler.

Finally make a liquid.rb file in config/initializers, require the extras/liquid_view path and register LiquidView to handle liquid templates. It should look like this:

1
2
3
4
# RAILS_ROOT/config/initializers/liquid.rb

require 'extras/liquid_view'
ActionView::Template.register_template_handler :liquid, LiquidView

Ta-da! Now you can render liquid templates from any location!

November 29, 2009

Authlogic, RSpec and :priority_record=>nil... wtf.

I think Authlogic is great. I think RSpec is great, but damn did I ever give myself a confusing error. My view specs were passing so I moved onto the controllers. The controller specs passed so I moved onto the models. After the models passed I tested all of the specs and found that I had broken the controllers some how.

When running my SessionsController tests I’d get an error like this:

1
2
3
<UserSession (class)> received :new with unexpected arguments
  expected: ({:password=>"valid-password", :login=>"dane"})
    got: ([{:priority_record=>nil}, nil])

At other times I’d get:


Mock "UserSession_1050" received unexpected message :priority_record= with (nil)
Read the rest of this entry

October 28, 2009

Ajax responses with Rails partials

I was working on a Rails app last night and hit a problem. I thought I’d share the problem and solution.

I had a form process an Ajax call on submit and evaluate the response text. I use jQuery so keep that in mind when you read the example JavaScript code.

1
2
3
4
5
6
// main.js
$('form[data-remote=true]').submit(function(){
  $form = $(this);
  $.post($form.attr('action'), $form.serialize(), false, 'script');
  return false;
});

You’ll notice the “data-remote=true” part. Disregard that. It’s just something coming down the pipes in Rails 3. So the JavaScript works. My controller works and renders the appropriate view.

1
2
// update.js.erb
$('#entries ol').append('<%= render(:partial => "entries/item", :locals => { :entry => @entry, :list => @list }) %>');

Thats the view rendered by the controller. You’ll see the view renders a partial within it.

1
2
3
4
5
6
7
8
<!-- entries/_item.html.erb -->
<li class="entry<%= cycle('', ' alt') %>" id="entry-<%= entry.id %>">
  <menu>
    <li><%= link_to "Update #{entry.name}", list_entry_path(list, entry), :class => "update" %></li>
    <li><%= link_to "Remove #{entry.name}", list_entry_path(list, entry), :class => "destroy" %></li>
  </menu>
  <p><%= entry.name %></p>
</li>

Well everything looks pretty good, but I kept getting the JavaScript error “unterminated string literal.” This is due to the line breaks in the entries/_item partial.

1
2
3
4
5
6
7
8
// will work
$('#entries ol').append('<li>\n\tThis is a new line\n\tThis is a second line\n</li>');

// this will not work
$('#entries ol').append('<li>
  This is a new line
  This is a second line
</li>');

To fix this I modified my update.js.erb view slightly. I added gsub("\n","").

1
2
// update.js.erb modified
$('#entries ol').append('<%= render(:partial => "entries/item", :locals => { :entry => @entry, :list => @list }).gsub("\n","") %>');

After pulling out the line breaks the JavaScript error disappeared. Hope this helps!

October 09, 2009

The RSpec Book

I recently finished The RSpec Book, well as much as you can finish a book in-progress. The RSpec Book is just great. It starts by explaining RSpec and Cucumber for Ruby applications and later progresses into BDD for Ruby on Rails. It’s a must read for anyone that wants to learn RSpec.

September 26, 2009

jQuery, me and form validation

Whether they know it or not anyone that has used the internet has experienced form or content validation. The purpose of content validation is to preserve the integrity of the application or service. Entering “100” as your first name wouldn’t make much sense. Trying to email “ABC-123?” wouldn’t make sense either. To prevent this from happening we can validate content in all sorts of ways, but the most important thing to remember is define what you will allow and not what you wont. For the examples to come I’ll be using the lovely Mary Jane Watson.

On the web there are two locations were validation can happen, on the server or in the browser. The application receives the content and validates it to determine whether to perform the next action or not. This is server-side validation. There is also client-side validation, handled by the browser. This is approach is done with JavaScript. Server-side validation is required, but client-side validation isn’t. Even though client-side validation isn’t required I can think of more reasons to do it than not. From a usability standpoint client-side validation is excellent. The user should receive feedback indicating whether or not content entered is allowed. Twitter does this with their sign up form as you type. Facebook gives feedback after you hit submit. Both are acceptable approaches. It also reduces the load on your server. By checking the user’s content before sending it to the server reduces the amount of work your server has to do. This is great because the server can spend those unused resources elsewhere. So now that we’ve seen two real world examples and understand the server benefits let’s get started validating with JavaScript.

Read the rest of this entry

September 02, 2009

Netflix, you had me at hello

I love Netflix. They provide an excellent service, a simple system and they stream a handful of their movies! I’ve heard complaints about Netflix, but when I think about it… I have none. The other evening I received an email that just reenforces why I am a very happy customer.

Netflix Email

They aren’t waiting for me to contact them saying I have a problem. They’re making the effort and contacting me saying, “Hey we had a little problem. Did it affect you?” They’re trusting me to redeem the credit if I was in fact affected by the technical issue. Who else does that?

Way to go Netflix team! I had no reason to leave, but I have yet another reason to stay.

August 12, 2009

fields_for in Rails, but no one mentions it (part 2)

Just an addition to my previous post on using fields_for.

A second approach to the same issue of working with the params data would be to utilize the attr_accessible method in the model.

1
2
3
class Page < ActiveRecord::Base
  attr_accessible :name
end

Using attr_accessible indicates what values of the model can be mass assigned. That I’ve only set :name, no attempt will be made to write the content portion of params. You can simply do the following:

1
2
3
4
5
6
7
@page = Page.new(params[:page]) # create the page
content = @page.contents.build(params[:page][:page][:content]) # create the content

if @page.valid? and content.valid?
  @page.save
  content.save
end

Both approaches work, but this will keep the controller clean.

August 09, 2009

fields_for in Rails, but no one mentions it

I was laying out a form for a page model last night. Each page has_many :contents. That’s straightforward enough, but when it came to the view I wanted to present the fields from page and the associated content model. That way the user can enter all of the necessary content, for both models, on a single page.

The Rails API explains fields_for very well, but there is no information on how the controller should act. I couldn’t find anything on the controller aspect anywhere. So this is what I’ve come up with.

The posted form looks like this.
1
2
3
4
5
6
params = {
  "page" => {
    "name" => "My Sweet Page",
    "content" => { " block"=> "This is why my page is so sweet" }
  }
}

You can’t just throw params[:page] into the Page model and save it because that will fail. It fails because content is an associated model and does not exist in the page table.

1
2
@page = Page.new(params[:page])
@page.save! # fails here

What you’ll need to do is remove the content data from params before adding it to Page, but make sure you hold on to it so you can create the content block.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
params_content = params[:page][:content] # get page content
params[:page].delete :content # remove content from page

@page = Page.new(params[:page]) # create the page
content = @page.contents.build(params_content) # create the content

if @page.valid? and content.valid?
  @page.save
  content.save

  flash[:notice] = "Your page has been sucessfully created."
else
  flash[:error]  = "There was a problem with the content you've entered."
end

This approach works pretty well. Alter the code to fit your needs, but this should work well enough for a prototype.

August 04, 2009

I'm lazy... but things are happening.

I don’t have much to write about. The work I’ve been doing has all been private, for now at least.

I have been toying around with jQuery, so a “Prototype vs. jQuery” post is on the way. Don’t expect any bashing of the two frameworks. I’m looking at the strengths of each and how they’ll best serve me or you.

As some may have seen, the Ruthless Mind blog has launched and has gotten a pretty decent response.

Simple Twits has exceeded 150 downloads, not bad for a week or two. I’ve also updated Simple Twits to allow for excluding blocked users from your followers list. This is great if you have some “inappropriate” accounts following you and you’d rather not display them on your site.

Hmmm… Not so much has happened with my challenge_response plugin, but some guys in the #rubyonrails channel on Freenode gave it a look and liked it. I’d love to hear if anyone has used it in their application.

I think Tim Harper’s role_requirement plugin is awesome, but it has some bugs. I’ll see if I can get some free time and lend a hand.

July 28, 2009

challenge_response: a better CAPTCHA

Would you rather your viewers spend the time deciphering a CAPTCHA image or simply add 2 + 3? Well I’m going with the latter.

Trying to figure out what those CAPTCHA images say drives me nuts. I find myself spending more time looking at the scribbled and crossed out letters than I am filling out the form. Maybe I’m just a poor reader :-)

Anyway, I wrote a Rails plugin called challenge_response. It’s available to for download from my GitHub repository.

The challenge_response plugin asks the viewer a randomly generated question like, “What does 1 + 3 equal?”, “What does 9 – 2 equal?” and “What letter comes after B?” Simple questions, yes, but it will ensure that a human is in fact filling out the form.

Integrating the plugin into your next or existing project takes less than 5 minutes. So check it out!

July 22, 2009

Simple Twits is up on Wordpress.org

I added Simple Twits to Wordpress.org’s Subversion repository today. I’m excited to have a Wordpress plugin out there, but I’m really excited about whatever feedback I might receive.

A little bit about the plugin

Simple Twits pulls the standard tweet feed, parses the feed for @username and URL’s and links them appropriately. It also allows users to showcase their followers.

For the bloggers that just want to use the plugin Simple Twits is very straightforward, but for those that like to tinker and tweak you can work directly with the Twitter data in a PHP array format.

I did my best to not say, “Simple Twits is simple.”

Check it out and tell me what you think!

July 13, 2009

My code doesn't validate when I use a target attribute...

The target attribute has been depreciated.

“But how can I make links open in a new window?”

The answer is JavaScript, but it’d be a bitch to add an onclick attribute to every external link, so I wrote something with Prototype to do it for me.

1
2
3
4
5
6
7
8
9
10
11
12
13
document.observe('dom:loaded',function(){
  var domain = document.domain.sub('^http://','').sub('^www.',''); // get domain
  $$('a[href^=http]').each(function(el){ // get all links on the page
    var url = el.href.sub('^http://','').split('/').shift(); // get base url
    if(!url.match(domain+'$'))
    {
      el.observe('click',function(event){
        Event.stop(event);
        window.open(el.href); // and open
      });
    }
  });
});

It just checks the URL of your domain against the links on the page. If the link isn’t of your site window.open is called.

The only catch to the code is with sub-domains. The JavaScript looks at test.codequietly.com and codequietly.com as the same domain, since it kind of is.

Just a little something for ya.

July 01, 2009

Transformers, explosions and Megan Fox!!

I hope I’m not the only person willing to say, “I liked the Transformers 2 movie!”

This Yahoo! article summed up why not to like the movie, but why did I?

I didn’t go into the theater expecting a revelation or to find answers to life long questions. I wanted to be “wowed.” I wanted to see transforming robots, explosions, and Megan Fox for two and a half hours. And I did just that. It’s so much easier to not like something, but even after reading these negative reviews and plot hole breakdowns I’d still see the movie a second time. It was an all-around fun movie!

I will agree with any fan that says, “The movie didn’t follow the original story! They changed everything!” And that’s okay. When I’m in the mood for the original story I’ll dust off the cartoon and watch it. If I’d rather see a lot of special effects, bad ass robots doing bad ass things, and Megan Fox, I’ll put on Transformers 1 and 2.

I neglected to say anything about Shia LaBeouf’s character Sam or his parents. I really thought they were exceptional. Their job was to act like a family and they had me convinced. The dad has his great lines, “Smells like 40 thousand dollars a year.” The mom eating the pot brownies. Sam just feeling, “Get them away from me…”

Now why Sam would want to part with Bumblebee… I don’t know, but itis just part of the story. I don’t think I would ever want to part with a transforming, super powered, robot, killing machine, that’s also a hot car. But I still liked the movie.

Everyone can and will have their own opinion. This is just mine.