MVC and modules. Views telling models to behave

I was thinking today, it would be nice if a view could tell a model how to format it’s data for that particular view.

Kind of like, the view is bestowing instant, and temporary knowledge on the model for the duration of the views run.

It seemed to me that this would be more objecty than say a helper that formats a string format_my_string( my_string )

Instead, in my view. Lets assume I have a Building class that has a phone_number field

At the top of my view then

<% Building.include PhoneNumberFormat %>

The PhoneNumberFormat module could overwrite the getter methods of phone_number, fax_number etc to provide me with some nice formatting. Presumably I could also pass some parameters somewhere (not quite sure yet) so that I could tell the PhoneNumberFormat what kind of format I want.

Then my building objects, when I call <%= @building.phone_number -%> instead of <%= format_my_phone_number( @building.phone_number ) -%> to get the format that I want

Is this a nasty abuse of MVC?

Thanx for any pointers

Daniel N wrote:

I was thinking today, it would be nice if a view could tell a model how to format it's data for that particular view.

Kind of like, the view is bestowing instant, and temporary knowledge on the model for the duration of the views run.

It seemed to me that this would be more objecty than say a helper that formats a string format_my_string( my_string )

Instead, in my view. Lets assume I have a Building class that has a phone_number field

At the top of my view then

<% Building.include PhoneNumberFormat %>

The PhoneNumberFormat module could overwrite the getter methods of phone_number, fax_number etc to provide me with some nice formatting. Presumably I could also pass some parameters somewhere (not quite sure yet) so that I could tell the PhoneNumberFormat what kind of format I want.

Then my building objects, when I call <%= @building.phone_number -%> instead of <%= format_my_phone_number( @building.phone_number ) -%> to get the format that I want

Is this a nasty abuse of MVC?

Yes!

In MVC, the model provides its data in neutral form and the view decides how to present it. This is a clean separation of concerns (and separation of concerns is one of the cornerstones of object orientation).

In your proposal, the model has to cater for a variety of ways of returning each of its attributes (these would all have to be able to vary independently) and the view has to know how to program the model to give the attribute values in the form you want.

Then what happens when you want a new format, that hadn't been anticipated by the model? You have to:

- add the new formatting capability to the model

- add the ability to switch to that format in the model

- do that switching in the view.

Bear in mind that there's practically no limit to the different ways in which data may be presented (graphical as well as textual), and it should be crystal clear that putting the knowledge of how to do this in the model is a recipe for disaster.

regards

   Justin Forder

Thanx for the feedback. I’ve responded below.

Cheers

Daniel N wrote:

Is this a nasty abuse of MVC?

Yes!

In MVC, the model provides its data in neutral form and the view decides how to present it. This is a clean separation of concerns (and

separation of concerns is one of the cornerstones of object orientation).

In your proposal, the model has to cater for a variety of ways of returning each of its attributes (these would all have to be able to

vary independently) and the view has to know how to program the model to give the attribute values in the form you want.

This would be via the include statement

<% Building.include PhoneNumberFormat %>

The model knows nothing of formatting until the very last instant. Then immediately forgets at the end of the response cycle. Since the view is last, this is effectively; immediately forgets.

Then what happens when you want a new format, that hadn’t been anticipated by the model? You have to:

  • add the new formatting capability to the model

Add a new format to the mixin module, not the model

  • add the ability to switch to that format in the model

The view would control which module is mixed in at runtime. This doesn’t need to be done in the model at all as far as I can tell.

  • do that switching in the view.

Bear in mind that there’s practically no limit to the different ways in

which data may be presented (graphical as well as textual), and it should be crystal clear that putting the knowledge of how to do this in the model is a recipe for disaster.

Perhaps your right. I was thinking along the lines of a form builder. I can (& I believe should) have a form defined in a view something like

<% form_for :user, :builder => MyBuilder do |f| %>

<%= f.text_field :name %>

<%= f.text_field :email %>

<%= f.password_field :password %>

<%= f.password_field :password_confirmation %>

<% end %>

I can have the builder generate whatever I like. I can even select the builder programatically if I want.

I can have that form rendered as a table, or as divs, spans whatever. All I need to do is build the builder the way I want. Then all my forms across the site are consistant.

My thinking was along the lines of this. If you have a DateFormatter module and you could tell it to format all dates of a model a particular way.

Again the syntax is not correct at the moment but something like this inside a view or in the views helper.

<% MyModel.include DateFormatter do %>

<% date_fields :all, “%d %m %y” %>

<% end %>

I’m not sure how any of the issues that you raised are a problem. Not saying they’re not… Just I don’t understand how they are yet.

Daniel N wrote:

Is this a nasty abuse of MVC?

Yes!

In MVC, the model provides its data in neutral form and the view decides how to present it. This is a clean separation of concerns (and

separation of concerns is one of the cornerstones of object orientation).

In your proposal, the model has to cater for a variety of ways of returning each of its attributes (these would all have to be able to

vary independently) and the view has to know how to program the model to give the attribute values in the form you want.

Thanx for the feedback. I’ve responded below. Cheers Sorri if this is a double post. I got a message to say that it wasn’t delivered.

This would be via the include statement

<% Building.include PhoneNumberFormat %>

The model knows nothing of formatting until the very last instant. Then immediately forgets at the end of the response cycle. Since the view is last, this is effectively; immediately forgets.

Then what happens when you want a new format, that hadn’t been anticipated by the model? You have to:

  • add the new formatting capability to the model

Add a new format to the mixin module, not the model

  • add the ability to switch to that format in the model

The view would control which module is mixed in at runtime. This doesn’t need to be done in the model at all as far as I can tell.

  • do that switching in the view.

Bear in mind that there’s practically no limit to the different ways in

which data may be presented (graphical as well as textual), and it should be crystal clear that putting the knowledge of how to do this in the model is a recipe for disaster.

Perhaps your right. I was thinking along the lines of a form builder. I can (& I believe should) have a form defined in a view something like

<% form_for :user, :builder => MyBuilder do |f| %>

<%= f.text_field :name %>

<%= f.text_field :email %>

<%= f.password_field :password %>

<%= f.password_field :password_confirmation %>

<% end %>

I can have the builder generate whatever I like. I can even select the builder programatically if I want.

I can have that form rendered as a table, or as divs, spans whatever. All I need to do is build the builder the way I want. Then all my forms across the site are consistant.

My thinking was along the lines of this. If you have a DateFormatter module and you could tell it to format all dates of a model a particular way.

Again the syntax is not correct at the moment but something like this inside a view or in the views helper.

<% MyModel.include DateFormatter do %>

<% date_fields :all, “%d %m %y” %>

<% end %>

I’m not sure how any of the issues that you raised are a problem. Not saying they’re not… Just I don’t understand how they are yet.

I just did this for fun, so don't take this as a recommendation to actually start using it or something :slight_smile:

class Person   attr_reader :phone

  def initialize(phone)     @phone = phone   end end

module PhoneFormatter   def self.extended(o)     (class << o; self; end).instance_eval do       alias_method :old_phone, :phone       define_method(:phone) { old_phone.gsub(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2-\\3")}     end   end end

irb(main):017:0> p = Person.new "5555551234" => #<Person:0x323eb0 @phone="5555551234"> irb(main):018:0> p.phone => "5555551234" irb(main):019:0> p.extend PhoneFormatter => #<Person:0x323eb0 @phone="5555551234"> irb(main):020:0> p.phone => "(555) 555-1234" irb(main):021:0> p.old_phone => "5555551234"

The PhoneFormatter module is pretty simple, but I'll explain it if you don't know the metaprogramming going on. When anything extends PF, the extended method gets called and is passed the object (usually a class) that was extended with PF. In this case, however, we're extending a Person object rather than the class itself. So then we get the metaclass of the person object, make an alias to keep the old phone method, and then define a new phone method that applies some formatting to the number returned from the old phone method.

In a nutshell, we're defining a couple singleton methods on p. So it won't affect any other instances of Person.

As I said, I just did that for fun. The main drawback I can immediately see is that it doesn't follow Rails conventions. To be honest though I don't see a whole lot of upside to it...maybe if you had several methods you wanted to format differently I guess, you could just knock em off in one fell extend rather than calling a bunch of helpers.

Maybe someone else would be willing to discuss the pros and cons of my approach (which I've never used, and don't intend to). I just decided to experiment, and I need my sleep :slight_smile:

Pat

It seem that what you are after is some kind of presenter object. Take a look at this article:

I just did this for fun, so don’t take this as a recommendation to actually start using it or something :slight_smile:

class Person attr_reader :phone

def initialize(phone) @phone = phone

end end

module PhoneFormatter def self.extended(o) (class << o; self; end).instance_eval do alias_method :old_phone, :phone define_method(:phone) { old_phone.gsub(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,“(\1) \2-\3”)}

end

end end

irb(main):017:0> p = Person.new “5555551234” => #<Person:0x323eb0 @phone=“5555551234”> irb(main):018:0> p.phone => “5555551234”

irb(main):019:0> p.extend PhoneFormatter => #<Person:0x323eb0 @phone=“5555551234”> irb(main):020:0> p.phone => “(555) 555-1234” irb(main):021:0> p.old_phone => “5555551234”

The PhoneFormatter module is pretty simple, but I’ll explain it if you don’t know the metaprogramming going on. When anything extends PF, the extended method gets called and is passed the object (usually a

class) that was extended with PF. In this case, however, we’re extending a Person object rather than the class itself. So then we get the metaclass of the person object, make an alias to keep the old phone method, and then define a new phone method that applies some

formatting to the number returned from the old phone method.

In a nutshell, we’re defining a couple singleton methods on p. So it won’t affect any other instances of Person.

Wow… Thanx for the effort. I see that the extended method in the documentation is not yet documented so this is indeed good to see it in action.

As I said, I just did that for fun. The main drawback I can immediately see is that it doesn’t follow Rails conventions. To be

honest though I don’t see a whole lot of upside to it…maybe if you had several methods you wanted to format differently I guess, you could just knock em off in one fell extend rather than calling a bunch of helpers.

I guess one of the main things that I’m thinking of is locale specific formatting. Dates, currency, Time, Phone numbers etc. The upside being mainly consistency across a view, and DRYness for choosing what that format is. Specific formatting requirements wouldn’t need to be scattered throughout code.

Mainly though it’s just a thought that I was having that I wanted to get some perspective on.

Maybe someone else would be willing to discuss the pros and cons of my approach (which I’ve never used, and don’t intend to). I just decided

to experiment, and I need my sleep :slight_smile:

I guess the only reason that I have been able to think of that this might not be a good idea, is when some method expects plain responses from a model, but recieves the formatted version instead. An adjacent method in the model for example, or in a different model/controller/helper/module may blow up in this situation.

Thanx for the link… It was interesting.