I have an habtm problem, which I just can''t figure out for the life of 
me. This is a continuation of another problem I had (on this thread: 
http://www.ruby-forum.com/topic/44286#9200), which someone was kind 
enough to help me with.)
To recap, I have tables Projects and Stages, with a habtm relationship. 
I have a table  Projects_Stages contains project_id, stages_id and an 
additional date_done field (containing the date the stage of the project 
was completed).
In addition to letting the user select the next stage of the project, I 
want them to be able to select the date that stage was completed, so I 
need a date select field on the page.
My models:
class Stages < AR
has_and_belongs_to_many :projects
end
class Projects < AR
has_and_belongs_to_many :stages
attr_accessor :newly_completed_stage_id
attr_accessor :stage_date_done
def before_save
	stages.push_with_attributes(Stage.find(newly_completed_stage_id.to_i), 
:date_done => stage_date_done) unless newly_completed_stage_id.blank?
end
end
My edit.rhtml page contains (as part of the form_tag):
<%= collection_select(:project, :newly_completed_stage_id, 
Step.find(:all) - @project.stages, :id, :description, {:include_blank => 
true}) %>
<%= date_select (:project, :stage_date_done, :order => [:day, :month, 
:year]) %>
The collection_select works just fine on its own. However, adding the 
date_select to the edit.rhtml page as shown above, returns the following 
error:
undefined method `klass'' for nil:NilClass
Trace shows parameters are being passed (some data omitted):
Parameters: {"commit"=>"Save",
"id"=>"1",
"project"=>{"stage_date_done(3i)"=>"13",
"newly_completed_step_id"=>"5",
"stage_date_done(1i)"=>"2005",
"stage_date_done(2i)"=>"12"}}
If I omit the date_select command in edit.rhtml and change my 
before_save method to ":date_done => Date.today", then everything
works
properly. So the problem is with the date_select command or the 
stage_date_done attribute. But I can''t find anything wrong with it, and
I can''t find any information on what the ''klass''
method is. So I''m
stuck! Is this just an habtm limitation or am I missing something?
The only thing I can think of is that date_select returns an array (as 
evidenced by the parameters passed), and that maybe I need to somehow 
define stage_date_done as an array using attr_accessor? However, I
can''t
find any way to do this (I have both the Programming Ruby and Agile 
books).
Thanks!
-- 
Posted via http://www.ruby-forum.com/.
zero halo wrote:> ... > attr_accessor :stage_date_done > ... > <%= date_select (:project, :stage_date_done, :order => [:day, :month, > :year]) %> > > The collection_select works just fine on its own. However, adding the > date_select to the edit.rhtml page as shown above, returns the following > error: > > undefined method `klass'' for nil:NilClass > ... > > The only thing I can think of is that date_select returns an array (as > evidenced by the parameters passed), and that maybe I need to somehow > define stage_date_done as an array using attr_accessor? However, I can''t > find any way to do this (I have both the Programming Ruby and Agile > books).There is no way for Rails to know that stage_date_done is of class Date, so multi-parameter assignments from posted parameters only work with database columns where the type can be determined. Possible solutions: 1. Extract the parameters manually, perhaps making use of AR''s extract_callstack_for_multiparameter_attributes method. 2. Somehow instantiate stage_date_done as a column in a way that Rails knows it''s not database-backed. 3. Instantiate stage_date_done as Date.new, and patch Rails around http://dev.rubyonrails.org/browser/trunk/activerecord/lib/active_record/base.rb#L1690 to look for the class of non-column attributes. -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James wrote:> 1. Extract the parameters manually, perhaps making use of AR''s > extract_callstack_for_multiparameter_attributes method.Best way to do this would probably be to use select_year, select_month, and select_day, use their field_name options, and three attr_accessors. -- We develop, watch us RoR, in numbers too big to ignore.
Mark Reginald James wrote:> Best way to do this would probably be to use select_year, > select_month, and select_day, use their field_name options, > and three attr_accessors. >Yep, tried that and it worked! I set each select_xxx with :prefix=>:project, :field_name=>:stage_xxx then created attr_accessor :stage_day, :stage_month, :stage_year and finally changes before_save to: def before_save stagedate = (stage_year + stage_month + stage_day).to_date stages.push_with_attributes(Stage.find(newly_completed_stage_id.to_i), :date_done => (stagedate)) unless newly_completed_stage_id.blank? end Interesting is that :date_done => stagedate returns a strange error (''unknown method < in Nil''). Only :date_done => (stagedate) works. Sure would be nice though if habtm had a way of verifying the attribute type in this sort of situation. Maybe Rails could be patched so that attr_accessor would accept a variable type? Thanks a lot, Mark, for your help. It''s almost taken me a long to try to solve this one little problem as to write my whole app! -- Posted via http://www.ruby-forum.com/.
zero halo wrote:> def before_save > stagedate = (stage_year + stage_month + stage_day).to_date > stages.push_with_attributes(Stage.find(newly_completed_stage_id.to_i), > :date_done => (stagedate)) unless newly_completed_stage_id.blank? > end > > Interesting is that :date_done => stagedate returns a strange error > (''unknown method < in Nil''). Only :date_done => (stagedate) works.stagedate = Date.new( stage_year, stage_month, stage_day ) would be better.> Sure would be nice though if habtm had a way of verifying the attribute > type in this sort of situation. Maybe Rails could be patched so that > attr_accessor would accept a variable type?Yes, I think Rails should allow models to define both DB-backed and non-DB-backed columns, so that both types can make use of validations and multi-parameter assignments. -- We develop, watch us RoR, in numbers too big to ignore.