Ruby on Rails: new vs. create vs. build difference
Oct5
Difference by examples. Let’s say that a User has_many Blogs and a Blog belongs_to a User.
$ ruby -v ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux] $ rails -v Rails 2.3.4
Last updated: 27.10.2009
new
New objects can be instantiated as either empty (pass no construction parameter) or pre-set with attributes but not yet saved (pass a hash with key names matching the associated table column names). In both instances, valid attribute keys are determined by the column names of the associated table — hence you can‘t have attributes that aren‘t part of the table columns.
Model.new
Requires additional save to save to database.
>> b = Blog.new({:title => "Test"})
+-------+---------+------------+------------+
| title | user_id | created_at | updated_at |
+-------+---------+------------+------------+
| Test | 1 | | |
+-------+---------+------------+------------+
1 row in set
>> b.save
SQL (0.1ms) BEGIN
Blog Create (0.3ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 04:35:20', 'Test', '2009-10-27 04:35:20', 1)
SQL (1.9ms) COMMIT
=> true
New and associating through <<
The object is saved to the database after adding the association using <<.
>> u = User.first
>> b = Blog.new({:title => "Test"})
+-------+---------+------------+------------+
| title | user_id | created_at | updated_at |
+-------+---------+------------+------------+
| Test | 1 | | |
+-------+---------+------------+------------+
1 row in set
>> u.blogs << b
SQL (0.1ms) BEGIN
Blog Create (0.4ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 04:41:15', 'Test', '2009-10-27 04:41:15', 1)
SQL (11.6ms) COMMIT
Blog Load (0.4ms) SELECT * FROM `blogs` WHERE (`blogs`.user_id = 1)
+----+---------+---------+---------+---------+
| id | title | user_id | crea... | upda... |
+----+---------+---------+---------+---------+
| 6 | Test | 1 | 2009... | 2009... |
+----+---------+---------+---------+---------+
1 row in set
Calling new on an association
When calling new on an association, it will create the object with the foregin key correctly set, but will not save it to the database (not even when parent is saved). The created object must be saved manually with save.
>> u = User.first
>> b = u.blogs.new({:title => "Test"})
+-------+---------+------------+------------+
| title | user_id | created_at | updated_at |
+-------+---------+------------+------------+
| Test | 1 | | |
+-------+---------+------------+------------+
1 row in set
>> u.save
SQL (0.1ms) BEGIN
SQL (0.2ms) COMMIT
=> true
>> u.blogs.all
Blog Load (0.1ms) SELECT * FROM `blogs` WHERE (`blogs`.user_id = 1)
0 rows in set
>> b.save
SQL (0.1ms) BEGIN
Blog Create (0.3ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 04:54:06', 'Test', '2009-10-27 04:54:06', 1)
SQL (3.9ms) COMMIT
=> true
>> u.blogs.all
Blog Load (0.3ms) SELECT * FROM `blogs` WHERE (`blogs`.user_id = 1)
+----+---------+---------+---------+---------+
| id | title | user_id | crea... | upda... |
+----+---------+---------+---------+---------+
| 7 | Test | 1 | 2009... | 2009... |
+----+---------+---------+---------+---------+
1 row in set
Build
build(associations, parent = nil)
Model.build
Build cannot be called directly on the model. It can only be called on associations.
>> Blog.build({:title => "Test"})
NoMethodError: SQL (9.0ms) SHOW TABLES
undefined method `build' for #
Calling build on an association
When calling build on an association, the new object will be saved when the parent is saved.
>> u = User.first
>> u.blogs.build({:title => "Test"})
+-------+---------+------------+------------+
| title | user_id | created_at | updated_at |
+-------+---------+------------+------------+
| Test | 1 | | |
+-------+---------+------------+------------+
1 row in set
>> u.save
SQL (0.1ms) BEGIN
Blog Create (0.3ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 04:56:10', 'Test', '2009-10-27 04:56:10', 1)
SQL (2.6ms) COMMIT
=> true
>> u.blogs.all
Blog Load (0.3ms) SELECT * FROM `blogs` WHERE (`blogs`.user_id = 1)
+----+---------+---------+---------+---------+
| id | title | user_id | crea... | upda... |
+----+---------+---------+---------+---------+
| 7 | Test | 1 | 2009... | 2009... |
+----+---------+---------+---------+---------+
1 row in set
Create
Creates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
Model.create
As the description of the method says, the object will be saved to the database if it passes validations.
>> u = User.first
>> Blog.create({:title => "Test"})
SQL (0.1ms) BEGIN
Blog Create (0.3ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 05:06:55', 'Test', '2009-10-27 05:06:55', NULL)
SQL (10.7ms) COMMIT
+----+-------+---------+-----------+-----------+
| id | title | user_id | create... | update... |
+----+-------+---------+-----------+-----------+
| 9 | Test | | 2009-1... | 2009-1... |
+----+-------+---------+-----------+-----------+
1 row in set
>> Blog.all
Blog Load (0.3ms) SELECT * FROM `blogs`
+----+-------+---------+-----------+-----------+
| id | title | user_id | create... | update... |
+----+-------+---------+-----------+-----------+
| 9 | Test | | 2009-1... | 2009-1... |
+----+-------+---------+-----------+-----------+
1 row in set
Note: In this case, there is no validation that the user_id field must be present, so such an object passes validation. If validation was added for user_id, the row would not be created in this case, because the object would not have passed validation. In that case, :user_id would have to be explicitly passed in the attrbiutes hash.
Calling create on an association
Works similar to build in this case (automatically adds the foregin_key - user_id in this case), but the new row is saved to the database already, and not only after the parent model is saved (as is the case with build).
>> u = User.first
>> u.blogs.create({:title => "Test"})
SQL (0.1ms) BEGIN
Blog Create (0.3ms) INSERT INTO `blogs` (`created_at`, `title`, `updated_at`, `user_id`) VALUES('2009-10-27 05:11:22', 'Test', '2009-10-27 05:11:22', 1)
SQL (0.7ms) COMMIT
+----+-------+---------+-----------+-----------+
| id | title | user_id | create... | update... |
+----+-------+---------+-----------+-----------+
| 10 | Test | | 2009-1... | 2009-1... |
+----+-------+---------+-----------+-----------+
1 row in set
>> u.blogs.all
Blog Load (0.3ms) SELECT * FROM `blogs` WHERE (`blogs`.user_id = 1)
+----+-------+---------+-----------+-----------+
| id | title | user_id | create... | update... |
+----+-------+---------+-----------+-----------+
| 10 | Test | | 2009-1... | 2009-1... |
+----+-------+---------+-----------+-----------+
1 row in set
>> u.save
SQL (0.1ms) BEGIN
SQL (0.2ms) COMMIT
=> true
Cheat cheet
Steps required for the object to be saved to database.
New
- Blog.new(…).save
- user.blogs << Blog.new(…)
- user.blogs.new(…).save – do not use, no practical use case
Build
- Blog.build – not possible
- user.blogs.build(…), user.save – both are required to save to DB
Create
- Blog.create(…)
- user.blogs.create(…)
Things I love about Google Chrome
May4
(when i was searching for a pic to use with this post, I realized Chrome supported skins, which I haven’t known until now)
- It’s SO fast Firefox can just hide in its little corner.
- I love how they placed the tabs into the titlebar, it just saves so much space and is rarely problematic.
- You can just drag a tab out of the window and make it its own window. It comes handy sometimes.
- Open in new tab is the first item in the right click context menu, unlike Firefox where it’s second (after Open in new window). I think the placement is just superior in Chrome.
- Why have a bookmarks menu when you can just list the bookmarks at the end of the Bookmarks toolbar? It’s just genious how they managed to save so much space on such simple things. After you start using it, you start wondering why all other browsers don’t follow this design.
- There is no search input box, you just enter the search query into the address bar instead. Firefox has something like this but it sucks and it’s slow as hell. I do admit, however, that sometimes it sucks that Chrome tries to auto-complete what you type in into an address, so you have to press delete before enter to search for it. But this leads me to point nr. 7.
- Just enter the first few letters of the URL, and if you’ve visited it before, Chrome will auto-complete it with the most probable match. Just press enter to browse to the site – unlike Firefox where you’ll have to press the down key first. Why??!
Of course there are some things I do not like about Chrome, but I can live with them mostly because Firefox is so damn slow:
- No extension support.
- No support for client SSL certificates (like for banking).
- Not supported on Linux yet, which is a bit of a downside, but not so much for me. You can always use Opera on Linux, it’s still much faster than Firefox
- JavaScript error console like in Firefox?? Can’t find something like that, so I still have to debug all my JS code in Firefox…
PS: This isn’t really a feature I use often, but I think Chrome was the first browser to support the “incognito mode”. It’s a mode where no history or cookies are saved (useful for porn, he he).
What do you think about Chrome? Are you still using Firefox, and are you thinking of switching to another browser? I appreciate your input.
New idea for Windows Touch Remix
May3
I’m going to do a quick-dial feature for Windows Touch Remix. I want to keep the code nice so it’ll take me a few days to get there, but this is how it looks at the moment (and how it’s supposed to look, anyway):
Personally i kind of like the shading, what do you think?
F#.NET
May0
F#.NET is a new functional language from Microsoft. It looks very promising, and here you can see a very good video presentation Luca Bolognese gave about it.
![]()
Snippet of the day: C#.NET configuration files
May0
I’ll start with a longer snippet – handling configuration files in C#.NET. I used this in Windows Touch Remix.
This is the base class I use for my configuration classes:
[Serializable()]
public class XmlConf
{
public static T FromFile<T>(string filename)
{
if (!File.Exists(filename)) return default(T);
XmlSerializer ser = new XmlSerializer(typeof(T));
StreamReader fs = new StreamReader(filename);
T t = (T) ser.Deserialize(fs);
fs.Close();
return t;
}
public void Save(string filename)
{
XmlSerializer ser = new XmlSerializer(this.GetType());
StreamWriter fs = new StreamWriter(filename, false);
ser.Serialize(fs, this);
fs.Close();
}
}
Just subclass it and add your configuration properties:
[Serializable()]
public class MyConf : XmlConf
{
public int IntVal { get; set; }
public string StrVal { get; set; }
}
Make sure you use getters and setters like in the above example, so the values get serialized properly. Most .NET classes (like List) are serializable, but if you have properties of your own class, make sure they are serializable.
Here’s a usage example of saving and loading the configuration:
// Save
MyConf conf = new MyConf();
conf.IntVal = 100;
conf.StrVal = "hey";
conf.Save("my.conf");
// Load
conf = MyConf.FromFile<MyConf>("my.conf");
if (conf == null) new Exception("Configuration file not found.");
Console.WriteLine(conf.IntVal);
Console.WriteLine(conf.StrVal);
Windows Touch Remix
May1
I did some further work on my Windows Touch Remix project, which I’ll be presenting at the NTK (Microsoft NT Conference) in Portorož on the 25th (i think) of May.
Here is the screenshot of the current version:
These are some of the more important features:
- Can replace your desktop
- Works like a (hopefully) stylish Start Menu
- Can import apps simply by dragging them from Program Files
- Almost completely customizable
I’m also working on an online AppStore-thingy which would allow auto-configuration of apps, but more importantly provide nice big icons you can use.
If anyone knows how to make Windows not include those shortcut arrows in the icons if you’re extracting them from shortcuts, let me know (the problem is that the shortcut can be to a non-exe file or have a different icon than the exe does).
You can download WTR (Windows Touch Remix) here.
When I open Chrome my speakers start producing some noise
May0
What the hell? The second I open Google Chrome my speakers start producing a high pitch noise. When I close it, it stops. It doesn’t happen with Firefox and it doesn’t matter if Chrome’s loading a page or just standing still.

