I’m a Java refugee, who is a bit of a Ruby and Rails noob, but I’m
certainly enjoying myself and have had a bit of success in creating a
few RoR bits and pieces… however, I think I must be missing something.
I just get the feeling that, although I’ve read through a couple of good
books, there is something quite basic in RoR that I’m just not
‘getting’. So, here is a (mildly contrived) example of the sort of thing
I’ve been trying to do - maybe some experts out there could
metaphorically slap me on the back of the head and say “Duh!”
Firstly, I have a simple model:
create_table :uris do |t|
t.column :loc, :string, :null => false
end
create_table :links do |t|
t.column :uri_id, :integer, :null => false
t.column :text, :string, :null => false
t.column :color, :string
end
I’ve then used generate scaffold_resource to create the usual default
files, to which, I’ve made the following changes
uri.rb:
class Uri < ActiveRecord::Base
has_many :links
def to_s
loc
end
end
link.rb:
class Link < ActiveRecord::Base
belongs_to :uri
end
link_controller.rb:
def update
@link = Link.find(params[:id])
@uri = Uri.new(:loc=>params[:uri][:loc])
@link.uri = @uri
…
def create
@link = Link.new(params[:link])
@uri = Uri.new(:loc=>params[:uri][:loc])
@link.uri = @uri
… # (the rest is the same as the auto-generated code)
views/links/new.rhtml:
…
<% form_for(:link, :url => links_path) do |f| %>
Text: <%= f.text_field :text %>
<% fields_for :uri do |u| %>URL: <%= u.text_field :loc %>
<% end %>Color: <%= f.text_field :color %>
<%= submit_tag "Create" %>
<% end %> ...views/uris/new.rhtml:
…
<% form_for(:uri, :url => uris_path) do |f| %>
URI Loc: <%= f.text_field :loc %>
<%= submit_tag "Create" %>
<% end %> ...This seems to be working OK, although I’m fairly sure I’ve not gone
about it quite the right way (in terms of the best way of writing the
views and controller to manipulate the Uri model and it’s relationship
with Link).
If anyone has any comments on that, I’m all ears! But anyway, at least
it works…!
Incidentally, my Uri view didn’t work when I originally named the Uri
model Url… it failed at the line <% form_for(:url, :url => links_path)
do |f| %>. I’m guess some sort of naming conflict… any ideas what I
should have done on that, apart from changing the name of my model?
What I’m really struggling with, though, is this: I want to have default
values for my attributes. That is, values that a new Link object would
default to when it is instantiated. These would show up on the form when
a user asks to create a new object.
For a while, I tried using the before_create filter, but had no joy
until I realised that this inserts the default values if the attributes
are empty before saving the record to the database, which is too late
for me…
So, the most obvious place, I thought, was the initialize methods:
link.rb:
def initialize
super
@color=“#999999”
@text=“default text”
end
This doesn’t work. I’ve no idea why, it looks like it should work. I’m
setting the instance variables to a default value, yet when the “new”
form is displayed, the fields are blank.
I played around with a couple more permutations of this, but to no
avail…
The best that happens is that a) no default values are displayed, and b)
I get “wrong number of arguments (1 for 0)” when the create method is
called. Bah!
My next effort was to add my own reader methods:
link.rb:
def color
@color || “#999999”
end
def text
@text || “default text”
end
No joy here either. Again, it looks to me like these should work… I
don’t understand why they don’t. They system appears to be acting as
though these variables aren’t used, and/or these methods aren’t called,
but the way I understand everything I’ve read says that they are! I’m
sure they are - I’ve seen “password” and “password=” methods
overwritten in several different examples so that a hashed password can
be created and saved to the DB.
So, my next thought is that maybe whatever ActiveRecord sets @color to
does not evaluate to false, so my code always returns @color, and never
“#9999999”.
But:
def color
“#999999”
end
does not work either! Argh! In fact, now the following happens: I try to
create a new link. The form is displayed with no defaults. I enter some
values, and the object seems to be created properly. However, the value
“#999999” is displayed when I use the “show” view, and the value I
actually entered is displayed when I display the “edit” view.
OK, so IIRC, my next attempt was using something along the lines of
Text: <%= f.text_field :text, :value=>"default text" %>
Which looked promising until I wanted to use the same _partial files for both the edit and create methods... in which case, "default text" shows up even when editing an object that already has a value for that attribute.After much googling, I came across another idea. For some reason not
clear to me, this should work:
link.rb:
def text
self[:text] or “default text”
end
It doesn’t seem to work for me either. I’m not sure why it would, but
the blog I read it on seemed to think it did work, and so did the
comments on the blog, so I’ve no idea what I’m doing wrong.
Ho hum… My next idea is to set these default values in the controller.
This seems wrong to me - default values for a model ought to be defined
in the model, shouldn’t they? But by now, I just want to get the thing
working even if its not where I think it ought to be!
so, my next attempt is:
link_controller.rb
def new
@link = Link.new
@link.text=‘link_controller default text’
@link.color=‘#ffffff’
end
Yay! That worked. It’s not, IMO, the right place to put the code, but it
works, so I’m putting up with it for now…
But how do I get a default value for the Uri?
I try adding this line to my “new” method:
@link.uri = Uri.new(:loc=>‘www.example.com/example.html’)
It doesn’t work. At this point, I’m all out of ideas, and this is where
I decided that my understanding just has a big whole in it that needs
filling, so I’ve written this long post!
Whatever it is that I’m not ‘getting’, I think its causing me other
problems too. For example, if have a list of languages, and want to have
a select box to assign a language to a link, I’d assume that at some
point the “language_id=” method would get called, so I write:
def language_id=(lid)
self.language=Language.find(lid)
end
or
def language_id=(lid)
@language=Language.find(lid)
end
or
def language_id=(lid)
language=lid
end
or any number of permutations of this sort of thing, none of which are
wiping the scowl off my face!
Thanks for taking the time to read down this far in the post, and any
advice is much appreciated!