• Shortcuts : 'n' next unread feed - 'p' previous unread feed • Styles : 1 2

» Publishers, Monetize your RSS feeds with FeedShow:  More infos  (Show/Hide Ads)


Date: Wednesday, 06 Apr 2011 08:36

One thing I often wished to have when using Git was the ability to autocomplete Git commands and branch names. As I had to learn this week from Markus Prinz’ article A few of my Git tricks, tips and workflows, Git comes with an autocompletion script for the Bash shell.

But to use the autocompletion, you have to enable it. To do that, add the following snippet to your ~/.bashrc file (if you are using a Mac, see the aforementioned article):

source /etc/bash_completion.d/git

You can then either reload the .bashrc file with source ~/.bashrc or open a new shell to see the autocompletion in action.

Author: "cakebaker" Tags: "git"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 01 Apr 2011 14:51

Till recently I always used a for-loop when I had to iterate over an array in JavaScript. For example:

var myArray = [1, 2, 3, 4];

for (var i = 0; i < myArray.length; i++) {
    console.log(myArray[i]);
}

However, with ECMAScript 5 the Array object itself got some methods for iteration purposes. With those methods you often can write cleaner code than by using a for-loop. Let’s have a (short) look at those methods. For details, please follow the provided links.

forEach

The forEach() method calls the provided function for each array element. Using forEach(), we can rewrite the example from above to:

var myArray = [1, 2, 3, 4];

myArray.forEach(function (element) {
    console.log(element);
});

filter

The filter() method applies the provided filter function to each array element and returns a new array with all elements for which the filter function returned a true value.

For example, to get only the even numbers of an array we could write the following code:

var myArray = [1, 2, 3, 4];

var evenNumbers = myArray.filter(function (x) {
    return x % 2 == 0;
});
// evenNumbers is [2, 4]

every & some

The every() and some() methods are similar: whereas the every() method only returns true if the provided testing function returns a true value for each array element, the some() method returns true if there is at least one array element for which the testing function returns a true value. You can see the difference in this example:

var oddNumbers = [1, 3, 5, 7];
var mixedNumbers = [1, 2, 3, 4];
var evenNumbers = [2, 4, 6, 8];

oddNumbers.every(isEven); // returns false
oddNumbers.some(isEven); // returns false

mixedNumbers.every(isEven); // returns false
mixedNumbers.some(isEven); // returns true

evenNumbers.every(isEven); // returns true
evenNumbers.some(isEven); // returns true

function isEven(x) {
    return x % 2 == 0;
}

map

The map() method applies the provided function to each array element and returns an array with the results.

For example, to square all values of an array we can do the following:

var myArray = [1, 2, 3, 4];

var squared = myArray.map(function (x) {
    return x * x;
});
// squared is [1, 4, 9, 16]

reduce & reduceRight

The reduce() and reduceRight() methods reduce an array step-by-step to a single value by using the provided function and an optional initial value. It works in the following way: the first two array elements (or the initial value and the first array element) are passed as parameters to the provided function. The result of this function call plus the next array element are then used as new parameters for the function. And so on, until there are no more array elements left.

The difference between reduce() and reduceRight() is that reduce() iterates over the array from left-to-right whereas reduceRight() iterates in the opposite direction, from right-to-left.

Here is a simple example to calculate the sum of the values of an array:

var myArray = [1, 2, 3, 4];
var initialValue = 10;

myArray.reduce(add); // performs 1 + 2 + 3 + 4 and returns 10
myArray.reduceRight(add); // performs 4 + 3 + 2 + 1 and returns 10

myArray.reduce(add, initialValue); // performs 10 + 1 + 2 + 3 + 4 and returns 20
myArray.reduceRight(add, initialValue); // performs 10 + 4 + 3 + 2 + 1 and returns 20

function add(x, y) {
    return x + y;
}

That’s it. I hope I could give you an overview over the available iteration possibilities in JavaScript. Happy coding!

Update 2011-04-02: I found a site by Microsoft where you can test those methods in your browser: ECMAScript 5 Arrays

Author: "cakebaker" Tags: "javascript, node.js"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 10 Jan 2011 17:30

From emails I receive it seems like there is a bit of confusion about what the terms 2-legged OAuth and 3-legged OAuth mean. I hope I can clear up this confusion with this article (and don’t contribute more to the confusion…).

In short, they describe two different usage scenarios of OAuth involving two respectively three parties.

3-legged OAuth describes the scenario for which OAuth was originally developed: a resource owner wants to give a client access to a server without sharing his credentials (i.e. username/password). A typical example is a user (resource owner) who wants to give a third-party application (client) access to his Twitter account (server).

On a conceptual level it works in the following way:

  • Client has signed up to the server and got his client credentials (also known as “consumer key and secret”) ahead of time
  • User wants to give the client access to his protected resources on the server
  • Client retrieves the temporary credentials (also known as “request token”) from the server
  • Client redirects the resource owner to the server
  • Resource owner grants the client access to his protected resources on the server
  • Server redirects the user back to the client
  • Client uses the temporary credentials to retrieve the token credentials (also known as “access token”) from the server
  • Client uses the token credentials to access the protected resources on the server

2-legged OAuth, on the other hand, describes a typical client-server scenario, without any user involvement. An example for such a scenario could be a local Twitter client application accessing your Twitter account.

On a conceptual level 2-legged OAuth simply consists of the first and last steps of 3-legged OAuth:

  • Client has signed up to the server and got his client credentials (also known as “consumer key and secret”)
  • Client uses his client credentials (and empty token credentials) to access the protected resources on the server

Above I used Twitter as an example, though strictly speaking, they don’t use 2-legged OAuth, but a variant of it. They not only provide the client credentials but also the token credentials (see also Using one access token with OAuth).

As you have seen, 2-legged OAuth is nothing new, it is simply using OAuth in a different scenario than it was designed for. And hence you can use (almost?) all existing OAuth libraries for 2-legged OAuth, too.

Author: "cakebaker" Tags: "oauth"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 08 Dec 2010 15:53

There is a new bugfix release of the OpenID component available: https://github.com/cakebaker/openid-component/downloads.

This release fixes a bug in the isOpenIDResponse() method. So far this method only recognized OpenID responses from a GET request. But as I had to learn, there are OpenID providers (e.g. Hyves) responding with a POST request… So, if you use the isOpenIDResponse() method, please upgrade to the new version.

However, this bug not only affected the component itself but also the examples and the example application. They contained code that looked like:

if ($this->RequestHandler->isPost()) {
    // make OpenID request
} elseif ($this->Openid->isOpenIDResponse()) {
    // handle OpenID response
}

This snippet will fail if the response from an OpenID provider is a POST request. Instead it should look like:

if ($this->RequestHandler->isPost() && !$this->Openid->isOpenIDResponse()) {
    // make OpenID request
} elseif ($this->Openid->isOpenIDResponse()) {
    // handle OpenID response
}

Please fix this in your code if you followed the examples.

Thanks go to Sam Mousa for reporting this issue.

Author: "cakebaker" Tags: "cakephp, component, openid"
Comments Send by mail Print  Save  Delicious 
Date: Saturday, 04 Dec 2010 09:33

If you are using Vim you already know the meaning of the “j” and “k” keys: they navigate one line downwards resp. upwards. Some websites like The Big Picture adopted this functionality to provide an easy way to navigate, in the case of The Big Picture to jump from photo to photo.

As I wanted to use the same functionality and didn’t find an existing solution I wrote a simple jQuery plugin for this purpose: jquery-jknavigable. Its usage is pretty simple, to make the posts of a blog navigable with the “j” and “k” keys you would use the following code:

$('.post').jknavigable();

By default the active element is marked with the class “active” so you can style it differently. If necessary, you can specify your own class name:

$('.post').jknavigable({'activeClass': 'someClass'});

That’s it. Feedback is, as always, welcome.

PS: a good starting point for writing your own plugin is jQuery’s Plugin Authoring page.

Author: "cakebaker" Tags: "javascript, jquery, plugin"
Comments Send by mail Print  Save  Delicious 
Date: Sunday, 19 Sep 2010 14:24

My current testing tool of choice is Cucumber. Cucumber itself integrates well with other tools. One of those tools is Webrat, which allows you to access your application without a browser and to perform actions like clicking on a link or filling out forms. It works fine with Rails 2.3.x, but not with Rails 3 (at least I was not able to make it work, and on RailsPlugins.org the current version of Webrat, 0.7.2.beta.1, is listed as “Maybe [working] with Rails 3″). Fortunately, there is an alternative working with both Rails versions: Capybara. And so I decided to make the switch from Webrat to Capybara.

Before making the switch, I recommend to run your Cucumber tests to ensure all tests pass:

$ cucumber features

As usual when adding new dependencies, you have to modify the Gemfile of your app. Replace the Webrat entry with:

gem "capybara", "0.3.9"

and run:

$ bundle update

With Capybara installed, you have to setup Cucumber to use Capybara by running one of the following commands:

// Rails 2.3.9
$ script/generate cucumber --rspec --capybara

// Rails 3.0.0
$ rails generate cucumber:install --rspec --capybara

Now, you are ready to run the tests again. If you are lucky, all tests pass, which means there is nothing more to do. However, I think it is more likely you will get a bunch of errors and maybe even some failing tests.

The errors I got were “undefined method” errors. They are relatively easy to fix by replacing the no longer existing Webrat methods with their Capybara counterparts. In the following code block I list some examples:

# Webrat
field_with_id('openid_identifier').value.should =~ /invalid OpenID/
# Capybara
find_field('openid_identifier').value.should =~ /invalid OpenID/

# Webrat
response.should contain('Previous')
# Capybara
page.should have_content('Previous')

# Webrat
assert_have_selector('.author', :count => 1)
# Capybara
page.should have_css('.author', :count => 1)

# Webrat
assert_have_xpath("//span[@id='#{id}']", :content => expected_count)
# Capybara
page.should have_xpath("//span[@id='#{id}']", :text => expected_count)

The trickiest part to fix was the failing test. To test some “remember me” functionality I manually set a cookie, and this no longer worked with Capybara:

cookies[:remember_me_id] = remember_me_id

After some searching I found a Gist from Nicholas Rutherford in which he dealt with cookies. Thanks to his code I could set my cookie with the following snippet:

cookies = Capybara.current_session.driver.current_session.instance_variable_get(:@rack_mock_session).cookie_jar
cookies[:remember_me_id] = remember_me_id

And with that, my switch to Capybara was complete. Any questions?

Author: "cakebaker" Tags: "cucumber, ruby on rails, testing"
Comments Send by mail Print  Save  Delicious 
Date: Monday, 19 Jul 2010 14:23

Last week I received a mail from a user of the OpenID component in which he described that it wasn’t possible to login with OpenIDs from claimID and Blogger. After some debugging I found the reason for this problem: a bug in the isOpenIDResponse() method. The method only recognized responses from providers using OpenID 2.0, but not from providers still using the older OpenID 1.x… So, if you are using this method in your code, please upgrade to the latest version (v2010-07-17).

I also got asked whether there is an example application that shows the usage of the OpenID component. As I already use a very simple application to test the component manually, I pushed this application to GitHub (you can see the application in action on http://openid-example.42dh.com/). I hope this will make it easier for some of you to get started with the OpenID component.

Author: "cakebaker" Tags: "cakephp, component, openid"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 14 Jul 2010 14:10

A while ago I wrote about how you can group related constants in PHP5 by using a constants class:

class MyConstants {
    const AA = 'value';
    const BB = 'another value';
}

echo MyConstants::AA; // output: value

Now, while experimenting with JavaScript (or more precisely with Node.js) I got some constants in my code I wanted to organize with such a constants class. My first, albeit naive, approach looked like:

var sys = require('sys');

function MyConstants() {
    const AA = 'value';
    const BB = 'another value';
}

sys.puts(MyConstants.AA); // output: undefined

However, as you can see, this doesn’t work. One reason is that const “[c]reates a constant that can be global or local to the function in which it is declared.”. So it isn’t possible to create a constants class like I imagined…

This means we have to emulate a constants class by using static properties and relying on the naming convention that names of constants are uppercased (i.e. the “constants” are technically not constants and their value can be changed):

var sys = require('sys');

function MyConstants() {
}

MyConstants.AA = 'value';
MyConstants.BB = 'another value';

sys.puts(MyConstants.AA); // output: value

If there is a better approach, please let me know.

Author: "cakebaker" Tags: "javascript"
Comments Send by mail Print  Save  Delicious 
Date: Wednesday, 19 May 2010 07:51

As mentioned in the title, I released a new version of the OpenID component today. It’s a maintenance release: the only change is an update of the bundled PHP OpenID library from version 2.1.2 to 2.2.2. With this change you no longer have to patch the OpenID library if you are working with PHP 5.3.

To update, simply replace the OpenID component and the content of the “vendors/Auth” folder (and its subfolders) with the files from the zip archive.

You can download the new version from Github.

Author: "cakebaker" Tags: "cakephp, openid"
Comments Send by mail Print  Save  Delicious 
Sassy CSS   New window
Date: Saturday, 08 May 2010 13:13

Those who follow me on Twitter probably know about my love-hate relationship with CSS. To ease the pain of working with CSS I switched to Compass, a stylesheet authoring framework. With Compass, you write the stylesheets in Sass (Syntactically Awesome Stylesheets) instead of CSS. Sass is basically CSS without brackets and semicolons, as you can see in this example from the Sass website:

h1
  height: 118px
  margin-top: 1em

.tagline
  font-size: 26px
  text-align: right

However, with the upcoming Sass 3 (it is planned to be released on May 10, 2010) a new format gets introduced: SCSS (Sassy CSS). It is a superset of CSS, i.e. each CSS file is automatically a SCSS file (you simply have to change the file extension from “css” to “scss”). So the example from above in SCSS is just plain CSS:

h1 {
  height: 118px;
  margin-top: 1em;
}

.tagline {
  font-size: 26px;
  text-align: right;
}

Not that exciting, isn’t it?

Where SCSS shines is when it comes to the integration of the Sass features (nesting, variables, and mixins) into this format. The devs did a very good job to make it feel like those features are native CSS.

Let’s have a look at some examples.

Nesting:

#header {
  background: gray;
  a {
    background: white;
    color: black;
  }
}

Variables:

$background_color: gray;

#header {
  background: $background_color;
}

Mixins:

@mixin red_border($border_width) {
  border: $border_width solid red;
}

#box_a {
  @include red_border(5px);
}

#box_b {
  @include red_border(10px);
}

Personally I really like the new SCSS format, and I can only recommend to try it out for yourself.

Author: "cakebaker" Tags: "css, ruby"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 20 Apr 2010 14:52

Nowadays most computers come with more than one processor. And so it makes sense to use the additional processing power to speed up your tests by distributing them across the available processors.

One tool that helps with this is Hydra. It allows you to distribute tests across multiple processors and machines, and currently supports the Test::Unit, Cucumber, and RSpec frameworks. In this article I will focus on running Cucumber tests on a single machine.

As Hydra is distributed as a Ruby Gem its installation is pretty simple:

gem install hydra

After that, you have to add Hydra to the Rakefile of the respective project. And you have to specify the Cucumber task and the files it should use.

# Rakefile
require 'hydra'
require 'hydra/tasks'

Hydra::TestTask.new('hydra:cucumber') do |t|
  t.add_files 'features/**/*.feature'
end

As last step you have to create a “hydra.yml” file in the “config” folder of your project. Here you define whether the tests should run locally, and how many runners Hydra should start. Runners correspond to processors, and so the setting below is for a dual core machine.

# config/hydra.yml
workers:
  - type: local
    runners: 2

With everything set up, you can now run the tests with the following command:

$ RAILS_ENV=test rake hydra:cucumber

To verify whether there is really a speed gain when running the tests in this way you have to do some kind of a benchmark (see the example below), because running something on multiple processors doesn’t necessarily mean it is faster…

Happy testing!
 


For my (unscientific) benchmark I ran my test suite (consisting of 12 files with 43 scenarios and 193 steps) with the following commands five times and averaged the results:

$ time cucumber features
$ time rake cucumber
$ time RAILS_ENV=test rake hydra:cucumber

In the first scenario I ran the benchmark with no other user applications running, i.e. both processors were available for the task at hand. From the results you can see that using Hydra in such a scenario is the fastest solution.

cucumber: 24.1s
cucumber with rake: 31.4s
hydra:cucumber: 22.4s

In the second scenario I ran the benchmark in a typical development environment with many open applications, i.e. around 1.5 processors were available. This time, using Hydra is not the fastest solution, the overhead is bigger than the speed gain from having more than one processor .

cucumber: 25.9s
cucumber with rake: 34.3s
hydra:cucumber: 30.6s
Author: "cakebaker" Tags: "cucumber, performance, testing"
Comments Send by mail Print  Save  Delicious 
Date: Tuesday, 13 Apr 2010 15:13

In a recent comment John mentioned that the OpenID component doesn’t work with Google Apps OpenIDs. And he was right.

The reason it didn’t work is that Google introduced it’s own OpenID discovery protocol as they faced challenges not addressed by the current version (2.0) of the OpenID standard. And this means such OpenIDs are not recognized by current OpenID libraries. For this reason, Google provides with php-openid-apps-discovery an add-on to the PHP OpenID library.

I integrated this add-on into the OpenID component as an optional feature. You have to enable it with:

public $components = array('Openid' => array('accept_google_apps' => true));

I made it an optional feature because it introduces an additional step to the authentication process: the provided OpenID url is sent to Google to figure out whether it is a Google Apps OpenID. And this makes the authentication process a bit slower. Hence I think you should have a choice whether you want to use this feature.

The new version of the OpenID component doesn’t contain any other new features/bugfixes.

You can download the component from Github.

Enjoy!

Author: "cakebaker" Tags: "cakephp, openid"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 02 Apr 2010 09:08

When writing specs for your code, you often have to do some initialization. With RSpec I do this initialization in a “before” block as shown in the following example:

describe BlogPost do
  before do
    @blog_post = BlogPost.create :title => 'Hello'
  end

  it "does something" do
    @blog_post.should ...
  end

  it "does something else" do
    @blog_post.should ...
  end
end

However, recently I stumbled upon a cleaner approach in a presentation (from which I borrowed the examples in this article) by Jon Larkowski that makes use of RSpec’s let() method. With this approach, the example from above looks like:

describe BlogPost do
  let(:blog_post) { BlogPost.create :title => 'Hello' }

  it "does something" do
    blog_post.should ...
  end

  it "does something else" do
    blog_post.should ...
  end
end

At first this looked quite magic to me and I had no clue how it worked. Though a look at the source of the let() method reveals the magic (the code should be self-explanatory, or else please leave a comment):

def let(name, &block)
  define_method name do
    @assignments ||= {}
    @assignments[name] ||= instance_eval(&block)
  end
end

Happy RSpecing!

Author: "cakebaker" Tags: "bdd, rspec"
Comments Send by mail Print  Save  Delicious 
Date: Sunday, 17 Jan 2010 09:46

This weekend the RailsBridge people have organized a bugmash with the motto “Do One Thing for Rails 3″, and so I took the opportunity to experiment a bit with the coming Rails 3.

After following the instructions for creating a new Rails 3 app (using the –database=mysql parameter for the “rails” command) I noticed that the application tried to access the (not existing) production database. That was a bit strange, because I expected it to access the development database as I set the RailsEnv option of Passenger accordingly:

# for example in /etc/httpd/conf/httpd.conf
RailsEnv development

The reason this doesn’t work is because the generated application contains a “config.ru” file. In this case, Passenger treats the application as a Rack application and not as a Rails application. And so the RailsEnv setting is ignored as it is Rails-specific…

There are two ways to run the application in development mode: you can either remove the “config.ru” file (and keep the RailsEnv setting) or you can set the RackEnv option:

# for example in /etc/httpd/conf/httpd.conf
RackEnv development

Have fun with Rails 3 :)

Author: "cakebaker" Tags: "configuration, ruby on rails"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 31 Dec 2009 16:45

If you are using the PHP OpenID library (which is also used by my OpenID component for CakePHP), it is possible that you get an “Invalid OpenID” error when you try to login with the Google OpenID (https://www.google.com/accounts/o8/id), or any other OpenID that uses “https”.

In this case, the following steps might help to fix this issue:

  • Ensure you have Curl and OpenSSL installed
  • Enable the Curl and OpenSSL extensions in your php.ini (on Archlinux this file is found in /etc/php/):
    extension=curl.so
    extension=openssl.so
    
  • Restart your web server

Now the error message should disappear and you should be able to log in with the Google OpenID.

—-

That’s it for 2009. It was a rather lazy year on this blog from my side (I didn’t even manage to do a redesign…), and so I hope I will be a bit less lazy with writing on this blog in 2010.

Anyway, thank you for reading this blog, and for all your comments and emails. A Happy New Year everyone & cu in 2010 :)

Author: "cakebaker" Tags: "openid, php"
Comments Send by mail Print  Save  Delicious 
Date: Saturday, 12 Dec 2009 17:30

The OpenID Attribute Exchange specification (or AX for short) has been around for quite a while, though I ignored it so far because at the time it was introduced (almost) no OpenID provider supported it. However, after Yahoo! announced they support Attribute Exchange, and someone recently mentioned it in a mail, it was time for me to have a look at it.

AX is in principle the “big brother” of the Simple Registration Extension (or SReg for short). Whereas SReg only allows you to retrieve nine commonly requested pieces of information, AX allows you to retrieve any identity information. And theoretically it also allows you to store/update your identity information at your OpenID provider. But it seems like no OpenID provider supports this feature…

Let’s have a look at an example.

First the login method:

// app/controllers/users_controller.php
class UsersController extends AppController {
    public $components = array('Openid', 'RequestHandler');

    public function login() {
        $realm = 'http://'.$_SERVER['SERVER_NAME'];
        $returnTo = $realm . '/users/login';

        if ($this->RequestHandler->isPost()) {
            $this->makeOpenIDRequest($this->data['User']['openid_identifier'], $returnTo, $realm);
        } elseif ($this->Openid->isOpenIDResponse()) {
            $this->handleOpenIDResponse($returnTo);
        }
    }
}

The next step is to implement the makeOpenIDRequest() method. For each attribute we want to retrieve, we have to create an Auth_OpenID_AX_AttrInfo object with the respective attribute type. A list of possible types is available on http://www.axschema.org/types/. Though there are many types defined, OpenID providers usually only support a small subset of those types.

The “1″ we pass to the make() method specifies the number of values we want for this type. In this example it doesn’t make much sense to specify a value other than “1″, but for other types it is theoretically possible to have multiple values (for example you could have defined multiple email addresses). It is an optional parameter and by default it is “1″.

The last parameter specifies whether the value of the attribute is required for our application. This is simply a hint for the OpenID provider so it could display this attribute differently, but it doesn’t guarantee a value is returned. By default this parameter is “false”.

(Update 2010-04-19: Google requires that you set the fourth parameter of the make() method: a string with an alias for the attribute.)

private function makeOpenIDRequest($openid, $returnTo, $realm) {
    $attributes[] = Auth_OpenID_AX_AttrInfo::make('http://axschema.org/namePerson', 1, true);
    $this->Openid->authenticate($openid, $returnTo, $realm, array('ax' => $attributes));
}

Finally, we have to implement the handleOpenIDResponse() method. As we expect only one value for the attribute we specified, we can use either get() or getSingle() to retrieve its value. getSingle() returns the value whereas get() returns an array.

private function handleOpenIDResponse($returnTo) {
    $response = $this->Openid->getResponse($returnTo);

    if ($response->status == Auth_OpenID_SUCCESS) {
        $axResponse = Auth_OpenID_AX_FetchResponse::fromSuccessResponse($response);

        if ($axResponse) {
            debug($axResponse->get('http://axschema.org/namePerson'));
            debug($axResponse->getSingle('http://axschema.org/namePerson'));
        }
    }
}

That’s it.

You can get the new version of the OpenID component from GitHub. If you use SReg in your code and you want to update to this version, please make sure to adapt your code in the following way:

// old
$this->Openid->authenticate($openid, $returnTo, $realm, array('email'), array('nickname'));

// new
$this->Openid->authenticate($openid, $returnTo, $realm, array('sreg_required' => array('email'), 'sreg_optional' => array('nickname')));

Feedback is welcome :)

Author: "cakebaker" Tags: "cakephp, openid"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 27 Nov 2009 16:15

Thanks to the built-in AtomFeedHelper it is quite easy to generate an atom feed with Rails.

Here an example from the API:

# app/views/posts/index.atom.builder
atom_feed do |feed|
  feed.title("My great blog!")
  feed.updated(@posts.first.created_at)

  @posts.each do |post|
    feed.entry(post) do |entry|
      entry.title(post.title)
      entry.content(post.body, :type => 'html')

      entry.author do |author|
        author.name("DHH")
      end
    end
  end
end

The code should be self-explanatory (if not, please leave a comment).

Recently, I had two such views which were almost identical, the only difference was the feed title. And that’s of course not really DRY.

One possible approach to fix this “issue” is to set an instance variable with the feed title in the controller and render the same view in both cases. As I don’t like to set view titles (resp. feed titles in this case) in the controller, I decided to use a partial.

And so I put the code from above into a partial (plus changing the instance variable “@posts” to a local variable “posts” and introducing a new local variable “feed_title”), and tried to use this partial (app/views/shared/_feed.atom.builder) in the following way:

# app/views/posts/index.atom.builder
render :partial => 'shared/feed', :locals => {:feed_title => "My Posts", :posts => @posts}

Well, it didn’t work. No output was generated.

After experimenting a bit I found the following solution by moving the outer-most block definition from the partial to the views:

# app/views/posts/index.atom.builder
atom_feed do |feed|
  render :partial => 'shared/feed', :locals => {:feed => feed, :feed_title => "My Posts", :posts => @posts}
end

I don’t know whether this is the best solution (probably not), but it is definitely better than what I had previously ;-)

Author: "cakebaker" Tags: "ruby on rails, view"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 20 Nov 2009 08:05

Sometimes you want to make a button look like a link. For example, in an admin interface you might want to have “links” to edit and delete articles. The “edit” link will be a normal link. But for the “delete” link you “cannot” use a normal link, because a delete action changes the state on the server and hence it should be performed using POST. Therefore the need for a button.

Thanks to CSS it should be easy to make a button look like a link, that’s what I thought when I started. But as usual when I work with CSS, what seems to be easy is not that easy… Anyway, here is the solution:

First the HTML code. Nothing special here, the only thing to note is that I had to use a “button” instead of an “input” element due to some CSS issues with Konqueror.

<form action="/article/1" method="post">
  <p>
    <button type="submit" class="link"><span>Delete</span></button>
  </p>
</form>

And here the CSS (thanks to Natalie Downe for her article Styling buttons to look like links, from where I got some of the settings below):

button.link {
  -moz-user-select: text;
  background: none;
  border: none;
  cursor: pointer;
  color: blue;
  font-size: 1em;
  margin: 0;
  padding: 0;
  text-align: left;
  text-decoration: underline;
  overflow: visible;
  width: auto;
}

This worked fine in Konqueror, but in Firefox there was always a padding of 2px. And of course I had no clue why. As you can see in the CSS snippet above, the padding was already set to 0… Fortunately, I found the solution in a comment of the aformentioned article:

button::-moz-focus-inner {
  padding: 0;
  border: none;
}

To use such link-like buttons in your own application you have to adapt the CSS to your own needs.

Have fun :)

Author: "cakebaker" Tags: "css, html"
Comments Send by mail Print  Save  Delicious 
Date: Thursday, 12 Nov 2009 16:16

On mailing lists or in private mails I sometimes read statements like “I am sorry, but I am a newbie” or “Sorry for this newbie question”. And I always wonder why do those people apologize for not being proficient?

It is ok to be new and inexperienced with a framework/programming language/whatever. Everyone of us is from time to time in such a “newbie phase”. And this means you will ask “stupid” questions (of course after you have done your “homework”, i.e. searching on the internet, reading the documentation). It’s part of the learning process. And it’s nothing you have to apologize for.

Author: "cakebaker" Tags: "communication, learning"
Comments Send by mail Print  Save  Delicious 
Date: Friday, 23 Oct 2009 14:49

Today, Nate Abele, lead developer of CakePHP, announced in a cryptic tweet that he leaves the project. This comes shortly after Gwoo, the project manager, left the project, too. It seems like they started to work on a fork of Cake3 called “Lithium”. On Twitter people are a bit puzzled about those events, some even think it is the end of CakePHP…

I don’t know whether this will be the case, it is too early to say. But I doubt it. The project is still backed by the Cake Development Company, which employs some of the core contributors (Larry Masters aka PhpNut, Mark Story). That’s some guarantee that the show will go on. And of course there is a large community.

On the other hand I don’t know how many of the other contributors will remain. And the lack of (official) communication is also not that good for the confidence into the project. What happened? What will be the next steps? Who will take over those vacant roles? See also Matt Curry’s post on this matter.

Anyway, probably the best thing to do now is to drink tea and to wait until the dust settles…

Update (2009-10-23): an official statement has been published in the meantime.

Author: "cakebaker" Tags: "cakephp"
Comments Send by mail Print  Save  Delicious 
Next page
» You can also retrieve older items : Read
» © All content and copyrights belong to their respective authors.«
» © FeedShow - Online RSS Feeds Reader