ROR Newb question - multiple models, one form / populating drop-downs from tables

Good Afternoon.

I am creating a time tracking application as learning exercise.
Each Project has_many Worktracks, each Worktrack has_many tasks, each
Proect has_many tasks through Worktracks.

Everything is great - model works, views work, controller functions.

Problem is, how can I have a single view incorporating Projects,
Worktracks and Tasks, allowing for creating Worktracks within Projects
(for example) - in one view.

I can do this in irb using '<<', but trying to translate this into
Rails is proving problematic. Searching this forum, I found a
Pragmatic book chapter, but the solution was complex and blew up my
app - undoubtedly, I erred somewhere trying to implement it, but I
cannot determine where, and at this point, my learning curve is
flatlined.

Any suggestions for general approach would be welcomed - my ideal
solution would be to be able to mix @project, @worktrack and @task all
in the same structure.

As a side-issue, but related, I have a valid_values table that I am
trying to use to populate drop-down menus within tasks, etc - but
again, I can only populate via direct coding in the view, rather than
passing in an array from database query. I know it can be done, but
the 'how' is defeating me. I suspect the solution is simple, but non-
obvious to me.

Many thanks in advance for suggestions, and I will accept flames in
good cheer if accompanied by workable suggestions.

There are many approaches to this problem. Some involve setting up
the code in the controller, others use a "presenter." Google
presenter pattern for more info on that. The "build" method might be
what you are looking for. This is created as you define your model
relationships. If you use it, it sets the foreign key id properly.

#controller
def new
  @project = Project.new
  @worktrack = @project.worktracks.build
end

def create
  @product = Project.new(params[:product])
  @worktrack = @project.worktracks.build(params[:worktrack])

  if @project.valid? & @worktrack.valid?
    Project.transaction do
      @project.save!
      @worktrack.save!
    end
  else
    render 'new'
  end
end

If you name the attributes properly in the view, this sort of scheme
will work. The problem with it is that the controller will become
bloated quickly as you add more complexity. For example if you add
your tasks piece, it will require another instance variable,
validation, save, etc. This is where a presenter model can help clean
up the controller.

As for your second question. You are likely looking for a
"collection_select" helper.

You could do something like this...

collection_select(:post, :author_id,
Author.all, :id, :name_with_initial, {:prompt => true})

collection_select(:post(..this is the object), :author_id(...this is
the method), Author.all(...this is the collection), :id(...this is the
value), :name_with_initial(...this is the text displayed), {:prompt =>
true}(...this is an option))

Andrew

Many Thanks, Andrew.

The drop down is actually simpler than you indicated - it is all
string text that was validated on input. All I need to do is "select *
from valid_values where dropdown_to_be_populated = 'status' " and
populate the returned array of strings into the dropdown.

My confusion - where would I put the code to pull this information to
make it available to the 'Tasks' view - and in that view, how can I
tell the view to look at a table that is not 'Tasks', or if I pull the
array in a controller (Tasks controller?) how to pass that to the
view?

I realize this should be easy, as the PragProg book (Agile Web Dev)
has sections on multiple-table applications, but their examples never
mix two tables' data on one view except when defining a cart - and
then, there is nothing directly on point.

Thanks again -

SR

You can have a class method of ValidValues model (if that is what it
is called) named something like strings_for_selection which returns
the data for the dropdown box. Then in the view simply call
ValidValues.strings_for_selection. This keeps all the knowledge of
which strings are valid in the model.

Alternatively call the method in the controller so
@strings_for_selection = ValidValues.strings_for_selection
and then use this in the view. Not so good in my opinion as why
should the controller be bothered with this?

Colin

I agree with Colin above. Make a model level method to return the
data you wish to use in the view. Then within the view call
ValidValues.method_you_make.

Like he said, another option is to put this code in the controller,
but most of the time, the dropdown select menus have little to do with
the rest of the controller function. So placing it in the controller
(just to ensure proper MVC architecture) works but in my opinion gets
to be a bit of overkill.