DISQUS

Astrails - Hi End Web Technology: Astrails Let my controller go or useful impurity in software design.

  • Chris Eppstein · 2 months ago
    Generating a view from your model (to_xml) is the problem here and is the reason why you're needing access to controller methods from your model.

    I get around this by having models implement a method called canonical_url that returns an object like so:

    {:use_route => "article", :id => self.id}

    This hash can then be passed to url_for to generate a route. I think this is a good convention for apps like yours that are doing some CMS-y things and necessarily blurring the line between data and views.
  • ismasan · 2 months ago
    I'll be the first then. Why not use the presenter pattern? Something like:

    class ArticleWidgetPresenter

    delegate :link_to, :to => :controller

    def initialize(controller, article_id)
    @controller, @article = controller, Article.find(article_id)
    end

    def to_html
    # .. load a template, build a string, etc
    end
    end

    And then, in your controller action

    def widget
    @presenter = ArticleWidgetPresenter.new(self, params[:id])
    render :text => @presenter.to_html
    end

    You could even load the routing module and not need the controller at all.
  • astrails · 1 month ago
    I'll tell you why :)
    Lets say I have articles#index returning Article.paginate(:include => :comments).to_xml

    with current_controller both Article and Comment can access url_for inside their respective to_xml implementations, and all the rest is done by Rails / ActiveSupport

    With your presenter pattern I'll have like X times more code that is much harder to understand and maintain. not simpler.
  • Bauerpauer · 2 months ago
    "i.e. it won’t work from the console". Yuck. Since (I'm assuming) you're turning the article into XML for purposes of insertion into a larger document, it seems to me that you'd want to instantiate something else, like an ArticleXmlList, which would have a constructor that accepts a collection of articles and a site domain, that way it has everything it needs to build the list you're looking for.

    ArticleXmlList.new(Article.all, request.domain).to_s

    Doesn't use Rails' url helpers, but its easily testable, doesn't know about more than it needs to, and works via the console just fine.
  • astrails · 1 month ago
    its is not supported on the console since it is by definition CAN'T be supported on the console. You don't know what domain to use when you are on the console.
    Where will your urls point to? http://localhost:3000/ ? :)
    Any other solution will require *some* piece of code holding a current_domain and being responsible for creating nice urls to your models. Since we already have such a piece called "controller" I don't see any reason to duplicate it somewhere else :)
  • qrush · 2 months ago
    Why couldn't this be a helper and tested with ActionView::TestCase?
  • angilly · 2 months ago
    +1 ismasan.

    Presenter pattern is real nice for this stuff. Especially when a few months down the road you need to write some script, data migration, cronjob, etc... that wants to use your model outside the rails environment.
  • astrails · 1 month ago
    presenter will not help for included associations.
    And having a presenter for every model that I want to return, effectively doubling my class count for the purpose on just to_xml is insane.
  • Jerome · 2 months ago
    "But sometimes, just sometimes, you need your link_to or html helpers working in the model."

    No. It's just stupid when you alter the patterns while there are other ways to accomplish what you need. It just means you don't understand what MVC stands for.
  • astrails · 1 month ago
    I do understand MVC, I'm just don't care about 'purity'. I care about 'utility'.
    'standard' way of implementing respond_to { |w| w.xml ..} in Rails is to call .to_xml.
    Its the easiest and cleanest (from readability/maintainability/dry/minimal_loc points of view) solution.
    If you need to generate urls inside it (especially if its in some included association) then having current_controller is IMHO the best possible option.