Components going out of style?


#1

I see in the new Agile Rails 2nd edition that components are going out
of style?

Is this so? has anybody abandoned the idea of components for helpers?

Specifically I’m considering a menu sytem for a website that depends
heavily on the users permissions to decide which menu options a user
would need to see. I thought that components, since they have the logic
in the controller and view in another file would be a good use of
components.

any input?


#2

On 5/24/06, Nola S. removed_email_address@domain.invalid wrote:

Specifically I’m considering a menu sytem for a website that depends
heavily on the users permissions to decide which menu options a user
would need to see. I thought that components, since they have the logic
in the controller and view in another file would be a good use of
components.

That may be a good seperation of concerns but it would be really slow.
Components are performance hogs, apparently.

I’ve heard plugins proposed as a replacement, but I don’t know how
plugins
implement views and routing. Anyone?


#3

I see in the new Agile Rails 2nd edition that components are going out
of style?

The problem with components is that they’ve never actually been in
style. We just forgot to tell people that. Our bad, now being
rectified.

Is this so? has anybody abandoned the idea of components for helpers?

Specifically I’m considering a menu sytem for a website that depends
heavily on the users permissions to decide which menu options a user
would need to see. I thought that components, since they have the logic
in the controller and view in another file would be a good use of
components.

I’d just make a helper that depends on an interface of a user model,
but is not bundled with it. So you rely on the fact that the user
model will have user.have_access_to?(section) or similar. Optionally,
you wrap it in a plugin that also includes a permissions include, so
you can do class User; include Permissions; end to get the methods you
need.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework


#4

I’ve heard plugins proposed as a replacement, but I don’t know how plugins
implement views and routing. Anyone?

In general, the position is that trying to make components with views
is not recommended. Instead, try to abstract the logic behind the
views into easy-to-use plugins such that using custom views will be
easy as pie.

If you for some reason can’t come to terms with this, I believe the
engine guys are there to help you out.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework


#5

I can see the logic behind moving away from components, but seeing as
i’ve been using them for a while, i’d be grateful for quick example of
the alternative.

If I have a shopping basket view that is shared in 2 places - say the
basket view page and a confirm order page. I would (normally) create a
controller action with an associated view and call it in the respective
basket/checkout views.

What would be the correct way to implement this without using the
component?

Advice and/or api/site links would be mucho appreciated :0)

Steve


#6

I can see the logic behind moving away from components, but seeing as
i’ve been using them for a while, i’d be grateful for quick example of
the alternative.

I’ll post the code here:

class ShopController < ActionController::Base
before_filter :set_cart

def index
  @products = Product.find(:all)
end

def buy
  @cart << Product.find(1)
  redirect_to :action => "index"
end

private
  def set_cart
    @cart = Cart.find(session[:cart_id])
  end

end

…and here’s the index.rhtml view:

My Magic Shop!

<%= render :partial => "product", :collection => @products %>
<%= render :partial => "cart" %>

The new Rails book has the full argument and justification as to why
this is the recommended approach instead of components.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework


#7

Oh right - that’s much better :0) I’ve been using a mix of partials and
components but now i think about it there isn’t really a need to.

My romantic attachement to paper books has stopped me upgrading my
‘Agile’ book but it’s looking more of a necessity now :0)

Cheers,

Steve


#8

On Wednesday, May 24, 2006, at 5:28 PM, Nola S. wrote:

any input?


Posted via http://www.ruby-forum.com/.


Rails mailing list
removed_email_address@domain.invalid
http://lists.rubyonrails.org/mailman/listinfo/rails

I recently implemented something like this with a partial.
In my case, I am also using the user/login engine combo, so I can do a
‘link_if_authorized’ or ‘authorized?’ block around sections of the menu
html.

It seems to work reasonably well, but I haven’t tested it for
performance.

_Kevin


#9

Noooooo! That’s the dark side talking to you, don’t listen.
Well i’ve got over it and just bought the PDF of the 2nd edition. I’m
not waiting until september for the paper version :0)

Oddly enough, i can’t actually find any reference to the deprecation of
components - the section on using components is still there. The
section at the beginning about sharing the cart view across with the
checkout however is not - i’ll have to have full read through i think.

I did however, realise (i think) what i should be doing. If i want to
display a list of links pages stored in the db for example, i create a
method in app/helpers/application_helper.rb called page_menu:

application_helper.rb

def page_menu
@pages = Page.find(:all)
end

Then i create a partial:

_page_menu.rhtml

<% page_menu %>

    <% @page.each do |page| %>
  • <%= page.url %>
  • <% end %>
...

This partial can then be used in other templates

<%= render :partial => ‘page_menu’ %>

Now this seems kinda cool because it would mean that i can use the
helper method in different partials that use the same data (say, two
cart view partials, one with form elements, the other a straight
display).

However, i don’t trust my own solution so it would be great if someone
could clarify this for me :0)

Cheers

Steve


#10

Stephen B. wrote:

Well i’ve got over it and just bought the PDF of the 2nd edition. I’m
not waiting until september for the paper version :0)

Oddly enough, i can’t actually find any reference to the deprecation
of components - the section on using components is still there. The
section at the beginning about sharing the cart view across with the
checkout however is not - i’ll have to have full read through i think.
I haven’t actually gotten to that part in the full book yet, and maybe
part of it is still being rewritten, but in the Intro portion it does
have a “Change Log” section which highlights the new Depot application
and some of its changes. One of the bulleted portions reads:

? It uses partials, rather than components (as components seem to be
on their way out).

So… There you go! Heehee… Seriously though, I honestly expect that
the code DHH posted earlier (I think to this thread even, but my brain
may be playing tricks on me) was probably taken straight from the book.
:slight_smile: I’m liking the new book so far…several code snippets seem to do
pretty much exactly what you typed in the previous message.

Also, I selfishly downloaded the code from the FamilyConnection project
(mentioned in another thread). It runs through some similar things in
the main layouts. It goes even further though. It has a custom method
“render_partials_array()” (or such) which loops through an array of
partials and renders them. This is set during various aspects of a
page’s living (typically in the controller, from what I’ve seen) and
very elegantly (in my opinion) resolves the side-menu content depending
on the role of the current user (guest, user, admin, etc)… For anyone
confused about partials, I recommend checking it out. It seems a good
way to do it. :slight_smile:

-Curtis


#11

On 5/24/06, Stephen B. removed_email_address@domain.invalid wrote:

My romantic attachement to paper books has stopped me upgrading my
‘Agile’ book but it’s looking more of a necessity now :0)

Noooooo! That’s the dark side talking to you, don’t listen. I got my
email about the update for 2nd Edition last night. Due to my position
in the queue I had to wait an entire 16 minutes for the gerbils to
pump out my copy, but…damn… It was worth the wait…

I’m not far enough into 2nd Edition yet, so I appreciate DHH dropping
the code here (since I’ve been struggling with this issue as well–in
relation to multiple apps sharing the same user tables and “user
dashboard” view). I look forward to reading more in the book though.
:slight_smile:

I see now that it would be best to render the user dashboard via a
partial that just gets dumped into the view. Maybe even in the
layout… It’s on nearly every page…and if it shouldn’t be I could
even utilize “display:none” for the user dashboard div… Probably
not perfectly clean…but…meh…

I’m curious to see how the menu gets rendered, I would imagine that’s
in the form of a partial called from the layout, but I could be wrong.
That may be an alternative way to do it. Perhaps some code that
checks for the existance of a hash object and renders a partial if
it’s there, or skips it if not (that could even be part of the partial
too, I suppose, so you wouldn’t have to recode that in every view that
might use it). Faster than components, and flexible enough if it’s
not needed (just ensure it’s null in the controller).


#12

Yeah - i’ve got through the partials section the new depot app. It
doesn’t address the issue i had but generally i’m loving the updates to
the 2nd edition so far - worth the re-investment :0)

The problem (with regards to the issue i had) with the example in the
depot app, is that it doesn’t seem to explain how logic code can be used
in partials (not a problem for the example obviously, but it’s a
sticking point if you want to do anything more complex).

For example:
You have a cart display on the cart page and the same thing repeated on
the order confirm page. This was in the 1st Agile book implemented
using a component, but is not in the 2nd edition.

In the 2nd edition, a cart preview is implemented using a partial:

— views/store/index
<%= render :partial => ‘cart’, :object => @cart %>

— controllers/store_controller
def index
@cart = session[:cart]
end

— views/store/_cart.rhtml
<% @cart.items.each do |item| %>

This is fine for this example. But if you try and do the ‘cart
displayed on order confirm’ i mentioned above, it gets a little messy:

— views/checkout/confirm_order.rhtml / views/cart/view.rhtml
<%= render :partial => ‘cart/cart’ %>

— views/basket/_cart.rhtml
<% @cart.items.each do |item| %>

In order for this to work, we would need to pass the @cart object to the
partial in each respective view, like this:
— views/checkout/confirm_order.rhtml / views/cart/view.rhtml
<%= render :partial => ‘cart/cart’, :object => @cart %>

In order for @cart to be available in the views, it would need to be
assigned in both the CartController::view and
CheckoutController::confirm_order actions - this seems at risk of
repetition.

I’ve implemented it by creating a helper method that the partial uses
(mentioned in my last post) - but that seems a bit un-rails-y and i
found it had an issue when i tried to assign something from the session.

I guess you could also create a method that the controllers could use
globally to assign this kind of thing:

— cart controller
def view
get_cart_view
end

— checkout controller
def confirm_order
get_cart_view

other stuff

end

— application controller
def get_cart_view
@cart = session[:cart]
end

… but again something about that isn’t right :0)

Man, that was a bit of a ramble - think i’ll have to write this all up
in a difinitive tutorial when i discover the ‘right’ way :0) I have a
slight feeling of ‘barking up the wrong tree’ though…

Cheers,

Steve


#13

In order for @cart to be available in the views, it would need to be
assigned in both the CartController::view and
CheckoutController::confirm_order actions - this seems at risk of
repetition.

That’s where the wonders of filters come in. Abstract to something
like set_cart, just like the code example I had showed.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework


#14

Ah right - i getcha.

Cheers,

Steve


#15

Stephen B. wrote:

Well i’ve got over it and just bought the PDF of the 2nd edition. I’m
not waiting until september for the paper version :0)

Oddly enough, i can’t actually find any reference to the deprecation of
components - the section on using components is still there. The
section at the beginning about sharing the cart view across with the
checkout however is not - i’ll have to have full read through i think.

Be aware that the book is being revised incrementally, so what you have
at present is a mixture of second edition pages (with red headers) and
first edition pages (with grey headers). Section 19.9, Layouts and
Controllers, hasn’t been revised yet.

regards

Justin


#16

For example, say I want to include a database driven web poll on certain
pages. Using the approach you describe would create both controller and
view dependencies on my web poll (even though say an article controller
really has nothing to do with a web poll). From a pure code perspective,
only needing to include the poll via render component just seems so much
cleaner.

For components where the content is completely unrelated to the rest of
the page and operates on different base objects, components of some
form may be advantageous. The cart example plays of the fact that in a
shop, the prime directive is to buy stuff. Thus, its not a tangential
concern, so its very natural that the cart is available most every
where.

And that’s been the far most common use of components I’ve seen. Where
essential pieces of the application, which uses data that the majority
of actions operate on (or which uses data that can be fetched from an
object which should be available always, like @person.preferences or
something), are chopped up. Components unnecessarily complicates such a
design and partials are usually a better fit.

But when you truly do have a case like the web poll, which is kind of
like a portlet, then the problem with render_component is mostly one of
implementation. Sounds like Ezra is exploring a way to deal with that
doing cells and I’ve even had thoughts of doing something like another,
internal HTTP request.

In any case, I consider components to be a rare specialty tool. Not a
general purpose architect-my-app-after-it kind of tool.


#17

David, I understand that components are going out, but I still think
they result in cleaner code than what you’re proposing here and clean
and easy to understand code is what rails is all about isn’t it?

For example I personally find:

  1. Extracting the set_cart out and then mixing it in to all controllers
    that need it, calling it via a before_filter, and then rendering a
    partial in all views that need it

to be a lot more complicated than:

  1. Calling render component in the views that need the component

For example, say I want to include a database driven web poll on certain
pages. Using the approach you describe would create both controller and
view dependencies on my web poll (even though say an article controller
really has nothing to do with a web poll). From a pure code perspective,
only needing to include the poll via render component just seems so much
cleaner.

-Todd
http://gabrito.com

David Heinemeier H. wrote:

In order for @cart to be available in the views, it would need to be
assigned in both the CartController::view and
CheckoutController::confirm_order actions - this seems at risk of
repetition.

That’s where the wonders of filters come in. Abstract to something
like set_cart, just like the code example I had showed.

David Heinemeier H.
http://www.loudthinking.com – Broadcasting Brain
http://www.basecamphq.com – Online project management
http://www.backpackit.com – Personal information manager
http://www.rubyonrails.com – Web-application framework


#18

Todd Huss wrote:

David, I understand that components are going out, but I still think
they result in cleaner code than what you’re proposing here and clean
and easy to understand code is what rails is all about isn’t it?

For example I personally find:

  1. Extracting the set_cart out and then mixing it in to all controllers
    that need it, calling it via a before_filter, and then rendering a
    partial in all views that need it

It isn’t complex to use the filters…

def ApplicationController
private
def set_cart
@cart =
end
end

def CartController < ApplicationController
before_filter :set_cart :only=>[:show]

def show
end
end

def CheckoutController < ApplicationController
before_filter :set_cart :only=>[:confirm_order]

def confirm_order
end
end

  • Peter

#19

On Sat, Sep 02, 2006 at 03:59:17PM -0000, DHH wrote:
[…]

But when you truly do have a case like the web poll, which is kind of
like a portlet, then the problem with render_component is mostly one of
implementation. Sounds like Ezra is exploring a way to deal with that
doing cells and I’ve even had thoughts of doing something like another,
internal HTTP request.

In any case, I consider components to be a rare specialty tool. Not a
general purpose architect-my-app-after-it kind of tool.

Last time I investigated this, it looked like everything I wanted out
of a component could be obtained by exposing
render_component_as_string, but I couldn’t figure out how to do
that.

Is there a reason that’s a bad idea?


- Adam

** Expert Technical Project and Business Management
**** System Performance Analysis and Architecture
****** [ http://www.adamfields.com ]

[ http://www.aquick.org/blog ] … Blog
[ http://www.adamfields.com/resume.html ]… Experience
[ http://www.flickr.com/photos/fields ] … Photos
[ http://www.aquicki.com/wiki ]…Wiki


#20

Last time I investigated this, it looked like everything I wanted out
of a component could be obtained by exposing
render_component_as_string, but I couldn’t figure out how to do
that.

Is there a reason that’s a bad idea?

Currently, I believe components just have some performance issues. I’d
encourage you to benchmark with and without to see whether it matters
in your case. And then be on the lookout for other/better ideas that we
could possibly do this. As well as keeping in mind that components are
not a general strategy for compartmentalizing things in Rails, unless
they have this portlet-type flavor we’re discussing.