Model nas Views

Buenas galera!

Projetando um sistema em Rails, me veio uma questão em mente: é uma má prática usar Models nas views?
Por exemplo: tenho minha classe período, que vai ter início e fim, e quero verificar se uma data está em um período pra fazer a validação, posso usar o modelo Periodo sem problemas? Ou qual seria a melhor maneira de fazer isso? Carregar um model pra view não sobrecarrega o sistema?

Vamos lá. Qualquer modelo em camadas diz que model e view não podem se comunicar, isso inclui, RoR.
Logo, você deve fazer essa validação invocando um controller (RoR torna isso muito fácil) e fazendo o processo adequado.

[quote=drsmachado]Vamos lá. Qualquer modelo em camadas diz que model e view não podem se comunicar, isso inclui, RoR.
Logo, você deve fazer essa validação invocando um controller (RoR torna isso muito fácil) e fazendo o processo adequado.[/quote]

Certo, e quanto aos helper selects que fazem sempre o uso da expressão ‘Model.all’ para preencher um combo?

Como vai @j0nny?

Num caso como esse, uma solução pode ser utilizar um helper_method (estou partindo do princípio de que não queremos deixar o uso do modelo vazar para view).

Um jeito bacana de fazer isso é definir um método em seu controller e marcar esse cara como um helper_method. Isto é, um método que foi criado para ser acessado pela view, e não para compor uma “action”.

Na prática, em seu controller, você teria algo como:

[code]class MeuController < ApplicationController

#actions

helper_method :todos
def todos
Model.all
end

end[/code]

E na view, você poderia invocar o método em seu helper como em:

Claro, sempre há a opção de definir um helper method “clássico”.

Um dos problemas de deixar seu acesso a modelos diretamente na view é que, com esse alto acoplamento, sua aplicação fica mais suscetível a mudanças, ainda que pequenas. Alterações no modelo passam a impactar no controller E na view… e assim por diante.

Pela pouca experiência que tenho tido com Rails, tenho visto que uma modificação no model compromete tudo, mesmo se você fizer todas as maracutais possíveis para não usar models nas views.

Mas não entendo que mal há nisso. Acho mais prático abrir mão do puritanismo nessas horas. O Rails faz de tudo pra tornar as modificações o mais painless possível.

Tudo bem @tnaires?

[quote=tnaires]

Mas não entendo que mal há nisso. Acho mais prático abrir mão do puritanismo nessas horas. O Rails faz de tudo pra tornar as modificações o mais painless possível.[/quote]

Até entendo que deixar de usar um “Model.all” no Rails soe realmente como um purismo. E concordo. Tem certas amarras que, no meu caso, trago de outros mundos OO. Mas no caso de um

será que nesse código a view não está muito curiosa sobre como organizamos nosso modelo? É nesse tipo de situação que acho que um helper “endereco_residencial” cai bem.

Que acha?

[quote=ricardo.valeriano]<%= @cliente.cadastro.endereco.residencial.rua %>

será que nesse código a view não está muito curiosa sobre como organizamos nosso modelo? É nesse tipo de situação que acho que um helper “endereco_residencial” cai bem.[/quote]
Nossa, nessa situação sua ideia ficaria melhor mesmo :smiley: Seria muita exposição pra view.

De qualquer forma, nem posso imaginar o impacto que causaria em outras partes da aplicação se mudássemos essa estrutura.

Obrigado pelas respostas @ricardo.valeriano.
E como faria, por exemplo, no meu cadastro de clientes, tenho um combo (select como vc colocou no exemplo), que precisa das informações de cidades, que por sua vez tem um controller Cidades.
Faria um helper em ClientesController chamado ‘cidades’?

Outro ponto, entre criar um arquivo Helper e criar um método helper no controller, qual a abordagem mais adequada?

Tudo jóia @j0nny?

Então, começa a entrar no ponto que o @tnaires levantou, se for só uma lista de cidades simplesmente, tem que avaliar o quanto vale a pena isolar em um helper.

Mas partindo do princípio que isso será realmente isolado, acho que o primeiro lugar onde eu colocaria o helper seria no controller porque sou preguiçoso. Depois, se aparecer em mais algum lugar (mesmo que seja apenas em mais um único canto) a necessidade de usar a mesma informação, já me preocuparia em tornar isso um helper method “clássico”.

Um outro cuidado que procuro ter é pensar no helper como um meio de campo entre model e view, o que também é outro assunto meio espinhoso… Mas minha ideia é tentar não levar muita lógica para dentro do helper também. Meus helpers costumam se apoiar nos models, sem grandes inteligências de negócio, mas com alguma lógica de visualização, para que a view em si fique mais enxuta.

Que acha da ideia?

[quote=ricardo.valeriano]Tudo jóia @j0nny?

Então, começa a entrar no ponto que o @tnaires levantou, se for só uma lista de cidades simplesmente, tem que avaliar o quanto vale a pena isolar em um helper.

Mas partindo do princípio que isso será realmente isolado, acho que o primeiro lugar onde eu colocaria o helper seria no controller porque sou preguiçoso. Depois, se aparecer em mais algum lugar (mesmo que seja apenas em mais um único canto) a necessidade de usar a mesma informação, já me preocuparia em tornar isso um helper method “clássico”.

Um outro cuidado que procuro ter é pensar no helper como um meio de campo entre model e view, o que também é outro assunto meio espinhoso… Mas minha ideia é tentar não levar muita lógica para dentro do helper também. Meus helpers costumam se apoiar nos models, sem grandes inteligências de negócio, mas com alguma lógica de visualização, para que a view em si fique mais enxuta.

Que acha da ideia?[/quote]

Exatamente, é essa a idéia, e talvez, por exemplo, as cidades listadas tenham que ser diferentes de acordo com a empresa do usuário, então na view teria que fazer algo como

Cidade.find_by_user current_user

o que acho muito responsabilidade para a view.

Outra questão, o helper chamaria os métodos direto do Model ou poderia passar pelo controller?

PS: Sou iniciante em Rails :lol:

Beleza @j0nny?

Então, na minha opinião você pode invocar a lógica dos models dentro de um helper, sem problema.

[quote=ricardo.valeriano]Beleza @j0nny?

Então, na minha opinião você pode invocar a lógica dos models dentro de um helper, sem problema.[/quote]

Certo, e no caso do meu primeiro exemplo, que tenho um modelo período, e quero verificar se uma data está dentro do período, vou usá-lo em várias views, criaria um helper só para período?
Ou criaria um método ‘is_date_in(date)’ no ApplicationHelper?

Então @j0nny, precisaria ver melhor exatamente qual é o uso disso em sua aplicação. De qualquer forma vou contribuir com meus 2 cents aqui, aí você vê o que acha da abordagem, beleza?

Desde já, como o código é de improviso aqui e não foi testado, pode ser que tenha algum probleminha… o html também não será o mais caprichado XD

Imagine a seguinte lógica: um cliente só pode ver seus pedidos, caso eles tenham sido realizados dentro de um determinado período (que me parece ser algo próximo ao que você esta buscando).

#app/views/clientes/show.html.erb Nome: <%= @cliente.nome %><br /> <%= pedidos_do @cliente %>

No modelo de clientes, eu faria a lógica de busca:

[code]#app/models/cliente.rb
class Cliente < ActiveRecord::Base
has_many :pedidos

def pedidos_feitos_no periodo
pedidos.where “data >= #{periodo.inicio} and data <= #{periodo.fim}” # um between também vai xD
end
end[/code]

Agora o helper não precisa ser muito inteligente sobre o que quer dizer um período, mas pode usar períodos, clientes, pedidos a vontade:

#app/helpers/clientes_helper.rb module ClientesHelper def pedidos_do cliente pedidos_html = "Pedidos: <div id='pedidos'>" periodo = Periodo.logica_marota_para_obter_periodo_dependendo_do_seu_dominio pedidos = cliente.pedidos_feitos_no periodo pedidos_html << render(pedidos) raw(pedidos_html << "</div>") end end

E para isso funfar, precisa de um partialzinho para exibir os pedidos:

[code]#app/views/pedidos/_pedido.html.erb

R$ <%= pedido.preco %>
[/code]

Uma outra observação que eu gostaria de fazer com a informação que você me passou até aqui: está me parecendo que uma data estar dentro de um certo período é algo crítico para a sua lógica/modelo. Se for o caso, eu provavelmente levaria essa preocupação para lá:

#app/models/periodo.rb class Periodo def contem? data # provavelmente sua lógica será mais complexa que isso... (@dt_inicio..@dt_fim).cover? data end end

O que acha dessa abordagem?

[quote=ricardo.valeriano]Então @j0nny, precisaria ver melhor exatamente qual é o uso disso em sua aplicação. De qualquer forma vou contribuir com meus 2 cents aqui, aí você vê o que acha da abordagem, beleza?

Desde já, como o código é de improviso aqui e não foi testado, pode ser que tenha algum probleminha… o html também não será o mais caprichado XD

Imagine a seguinte lógica: um cliente só pode ver seus pedidos, caso eles tenham sido realizados dentro de um determinado período (que me parece ser algo próximo ao que você esta buscando).

#app/views/clientes/show.html.erb Nome: <%= @cliente.nome %><br /> <%= pedidos_do @cliente %>

No modelo de clientes, eu faria a lógica de busca:

[code]#app/models/cliente.rb
class Cliente < ActiveRecord::Base
has_many :pedidos

def pedidos_feitos_no periodo
pedidos.where “data >= #{periodo.inicio} and data <= #{periodo.fim}” # um between também vai xD
end
end[/code]

Agora o helper não precisa ser muito inteligente sobre o que quer dizer um período, mas pode usar períodos, clientes, pedidos a vontade:

#app/helpers/clientes_helper.rb module ClientesHelper def pedidos_do cliente pedidos_html = "Pedidos: <div id='pedidos'>" periodo = Periodo.logica_marota_para_obter_periodo_dependendo_do_seu_dominio pedidos = cliente.pedidos_feitos_no periodo pedidos_html << render(pedidos) raw(pedidos_html << "</div>") end end

E para isso funfar, precisa de um partialzinho para exibir os pedidos:

[code]#app/views/pedidos/_pedido.html.erb

R$ <%= pedido.preco %>
[/code]

Uma outra observação que eu gostaria de fazer com a informação que você me passou até aqui: está me parecendo que uma data estar dentro de um certo período é algo crítico para a sua lógica/modelo. Se for o caso, eu provavelmente levaria essa preocupação para lá:

#app/models/periodo.rb class Periodo def contem? data # provavelmente sua lógica será mais complexa que isso... (@dt_inicio..@dt_fim).cover? data end end

O que acha dessa abordagem?[/quote]

Certo, seria mais ou menos isso mesmo.
Na verdade queria usar na validação, mas me equivoquei, pq na verdade isso seria responsabilidade do JS, certo?

De qualquer forma, agradeço a paciência e os esclarecimentos :slight_smile: