Struggling with rjs templates


#1

Hi all,
i’ve been reading the Agile Rails book (2nd ed), and I’m trying to write
custom versions of the various exercises as i go along.

In this particular example, i have 2 models: user and possession.
The user controller lists the users, and clicking on a user goes to
another action, which lists that users possessions.

That possessions list is done with:

<%= render :partial=>"pos",:collection=>@posessions %>

the pos partial looks like this:

  • <% form_remote_tag :url=>{:action=>:delete_pos,:id=>pos.id } do %> <%= pos.posession_name %> - <%= submit_tag "Delete" %> <% end %>

and the jrs template:
page.replace_html(“posession_list”,:partial=>“pos”,:collection=>@posessions)

When clicking on a “Delete” button, nothing happens in the browser
unless I refresh, and then the item has gone (i have included the
:defaults js).
In the rails console, I see this:

ActionView::TemplateError (Called id for nil, which would mistakenly be
4 – if you really wanted the id of nil, use object_id) on line #3 of
app/views/user/_pos.rhtml:
1:


    2:

  • 3: <% form_remote_tag :url=>{:action=>:delete_pos,:id=>pos.id } do %>
    4: <%= pos.posession_name %> - <%= submit_tag “Delete” %>
    5: <% end %>
    6:
  • I can see that id=>pos.id is causing the problem, but not sure why. I
    guess it’s trying to render the code for the object that has been
    deleted, but in my delete_pos action, I have this:
    Posession.delete(params[:id])
    @posessions = @user.posessions
    So the posessions array should be updated?

    any ideas what I’m doing wrong? Thanks for reading.


#2

Hi Oliver,

Oliver Oh wrote:

3: <% form_remote_tag :url=>{:action=>:delete_pos,:id=>pos.id } do %>
4: <%= pos.posession_name %> - <%= submit_tag “Delete” %>
5: <% end %>
6:

I can see that id=>pos.id is causing the problem, but not sure why.

My guess is that you’re not actually assigning an id to the form which
would
explain why you’re not seeing anything happen in the browser until you
do a
refresh. Get firebug and check out the DOM you’re creating.

Best regards,
Bill


#3

Bill W. wrote:

My guess is that you’re not actually assigning an id to the form which
would
explain why you’re not seeing anything happen in the browser until you
do a
refresh. Get firebug and check out the DOM you’re creating.

Best regards,
Bill

Hi Bill,
Is it the form that needs an ID or the div that will have its content
replaced?
The code generated in firebug looks like this:

  • Thanks for the reply.


#4

Hi Oliver,

Oliver Oh wrote:

Is it the form that needs an ID or the div that will have
its content replaced?

Depends on what you’re trying to do and I’m not real sure from what
you’ve
told us exactly what that is. In general, page.replace_html will treat
the
DOM element with the id you pass in as a ‘wrapper’ and will replace
everything inside it with the content you specify via the partial.

I’m a little confused about your use of a single form inside the
posession_list. I’d expected to see you iterating through the
collection in
your view. If you’re wanting to use a button to trigger the delete on
each
item, you could use a form to do it. Or you might want to check out
button_to_remote. Off the top, something like (untested)

<% @posessions.each do |@this_posession| %> <%= render :partial=>"pos" %> <% end %>

And then in the partial use @this_posession.id to put an id on the
element
you want to remove. But I’m assuming that removing the item from the
view
is what you’re trying to do. You’ll need to say more, and show the
relevant
controller code, for me to offer anything more concrete.

Best regards,
Bill


#5

Hi Robby,

Robby R. wrote:

I’d really discourage creating an instance variable and
passing it down to the partial like this.

While I agree that passing a local to the partial is an option, I wonder
why
you’d discourage the use of an instance variable in this instance. We
pass
instance variables up from the controller to the view. Why not let them
'bubble up" from the main view to partials? He doesn’t appear to be
doing
anything with it but setting a value to send back to an action. Looking
forward to hearing your thoughts.

Best regards,
Bill


#6

Bill W. wrote:

everything inside it with the content you specify via the partial.
<% end %>

And then in the partial use @this_posession.id to put an id on the element
you want to remove. But I’m assuming that removing the item from the view
is what you’re trying to do. You’ll need to say more, and show the relevant
controller code, for me to offer anything more concrete.

I’d really discourage creating an instance variable and passing it down
to the partial like this. You should consider using the locals hash in
this instance. If you’re using a partial, it’s safe to assme that this
partial is getting rendered somewhere else, correct?

I’d do something like this…

<% @posessions.each do |posession| %> <%= render :partial=> "pos", :locals => { :posession => posession } %> <% end %>

Good luck!

Robby


Robby R.
http://www.robbyonrails.com/


#7

Robby R. wrote:

anything with it but setting a value to send back to an action. Looking
your partials as somewhat like a method with parameters being passed.
Right now, you’re relying on variables that anything can access (and
potentially update)… therefore, increasing the risk that someone might
use the wrong instance variable in the wrong place or manner than it was
originally intended.

I hit send too soon. :wink:

I also would discourage from EVER setting an instance variable within a
view. There really isn’t a good really for doing this at all. Views are
not the place to do this, in my opinion.

Robby


Robby R.
http://www.robbyonrails.com/


#8

Bill W. wrote:

anything with it but setting a value to send back to an action. Looking
forward to hearing your thoughts.

It’s all about managing scope. After the block is finished, the instance
variable still exists, which means something else in the view and/or
controller can access it.

If it doesn’t need to exist beyond that scope, there isn’t any good
reason to pass it down. If you have partials a few files deep and are
relying on an instance variable, this would be discouraged. Think of
your partials as somewhat like a method with parameters being passed.
Right now, you’re relying on variables that anything can access (and
potentially update)… therefore, increasing the risk that someone might
use the wrong instance variable in the wrong place or manner than it was
originally intended.

Cheers,
Robby


Robby R.
http://www.robbyonrails.com/


#9

Hi Robby,

Robby R. wrote:

It’s all about managing scope.

Good explanation. I agree.

I also would discourage from EVER setting an instance
variable within a view. There really isn’t a good reason
for doing this at all. Views are not the place to do this,
in my opinion.

I agree in here too. OTOH, I think it’s sometimes a good idea to help
folks
along in their learning in steps.

Best regards,
Bill


#10

Robby R. wrote:

Robby R. wrote:

Bill W. wrote:
I also would discourage from EVER setting an instance variable within a
view. There really isn’t a good really for doing this at all. Views are
not the place to do this, in my opinion.

That should have read… “There really isn’t a good REASON for doing
this at all.”

…need some caffeine. :wink:


Robby R.
http://www.robbyonrails.com/