Values of instance variables set within an action of a controller are available in the template associated with that action. I was thinking (hoping?) that the values of instance variables set within a controller but outside of any action would be universally available to all the templates associated with that controller. Apparently that is not the case. Two questions: (1) Why is that? (2) Is there some way (other than using a global variable) that I can set a variable in a controller and have its value available to all templates associated with that controller? Thanks for any input. ... doug
On 27 Apr 2009, at 17:23, doug wrote:> > Values of instance variables set within an action of a controller are > available in the template associated with that action. I was thinking > (hoping?) that the values of instance variables set within a > controller but outside of any action would be universally available to > all the templates associated with that controller. Apparently that is > not the case. Two questions: (1) Why is that? (2) Is there some way > (other than using a global variable) that I can set a variable in a > controller and have its value available to all templates associated > with that controller? >it might clear things up if you pastied what you''ve been trying. Fred> Thanks for any input. > > ... doug > >
Doug Jolley wrote:> Values of instance variables set within an action of a controller are > available in the template associated with that action. I was thinking > (hoping?) that the values of instance variables set within a > controller but outside of any action would be universally available to > all the templates associated with that controller. Apparently that is > not the case. Two questions: (1) Why is that?Perhaps a more basic question is: why is the template able to access the private variables in the controller at all? In other words, if you define a ruby class like this: class A def initialize @var = 10 end end then all the other methods in class A can access @var, but an object of class B cannot access @var. I think a template is over in class B somewhere.> (2) Is there some way > (other than using a global variable) that I can set a variable in a > controller and have its value available to all templates associated > with that controller? >Sessions? -- Posted via http://www.ruby-forum.com/.
7stud -- wrote:> Doug Jolley wrote: > Perhaps a more basic question is: why is the template able to access the > private variables in the controller at all? In other words, if you > define a ruby class like this:Rails does some magic to make that happen. Here is a blog post that explains the basics of how this happens: http://www.neeraj.name/blog/articles/719-how-controller-and-view-share-instance-variables> then all the other methods in class A can access @var, but an object of > class B cannot access @var. I think a template is over in class B > somewhere.Yes, you are correct about this in the general case, but as you can see above Rails performs some additional work to simplify template development by coping ivars from the controller into the views.>> (2) Is there some way >> (other than using a global variable) that I can set a variable in a >> controller and have its value available to all templates associated >> with that controller? >> > > Sessions?I would think avoiding global variable would be a very smart thing to do. Session variables might be what you want. It really all depends on what you''re trying to do. Generally speaking if you find yourself fighting against Rails you''ve probably got a design problem. Of course, there''s exceptions to every rule. -- Posted via http://www.ruby-forum.com/.
> Rails does some magic to make that happen. Here is a blog post that > explains the basics of how this happens: > > http://www.neeraj.name/blog/articles/719-how-controller-and-view-shar...Thanks. The blog post explains the magic that Rails uses to make the instance variables contained in an action visible in the view associated with that action. I just need to figure out how I can set a value in a controller and make that value available to all of the views in that controller. Thanks again. ... doug
I am having difficulty imagining why you would want an instance variable of a controller that is not associated with an action, what else do controllers do? Are you sure it is not an instance variable of a model that you should be using? Colin 2009/4/27 djolley <ddjolley-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > > Rails does some magic to make that happen. Here is a blog post that > > explains the basics of how this happens: > > > > http://www.neeraj.name/blog/articles/719-how-controller-and-view-shar... > > Thanks. The blog post explains the magic that Rails uses to make the > instance variables contained in an action visible in the view > associated with that action. I just need to figure out how I can set > a value in a controller and make that value available to all of the > views in that controller. > > Thanks again. > > ... doug > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Is this something that you can do with a before_filter?
> I am having difficulty imagining why you would want an instance variable of > a controller that is not associated with an action, what else do controllers > do?The thing is that this particular instance variable is associated with *ALL* of the actions of the controller. I want to be DRY and only specify the value of the instance variable once and have that value available in all of the views associated with each of the actions of that controller.> Are you sure it is not an instance variable of a model that you should > be using?I don''t think so. Models extend from ActiveRecord::Base. Therefore in my nieve view of the Rails world, models are only used with databases. I don''t have a database involved. I just want to pass a common value from the controller to the views and I don''t want to have to redundantly specify that value in each of the actions. Thanks for the input. ... doug
> Is this something that you can do with a before_filter?I think you may be onto something. Conceptually, it sounds like your suggestion should work. I''m just not sure that I know how to go about implementing it. I''ll play around with the concept and post if I am successful. In the meantime, if anyone has any specific input on precisely how to do this, I''d sure love to hear it. Thanks for the input. ... doug
In that case would an @variable in before_filter, rather than an instance variable do? Colin 2009/4/28 djolley <ddjolley-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > > I am having difficulty imagining why you would want an instance variable > of > > a controller that is not associated with an action, what else do > controllers > > do? > > The thing is that this particular instance variable is associated with > *ALL* of the actions of the controller. I want to be DRY and only > specify the value of the instance variable once and have that value > available in all of the views associated with each of the actions of > that controller. > > > Are you sure it is not an instance variable of a model that you should > > be using? > > I don''t think so. Models extend from ActiveRecord::Base. Therefore > in my nieve view of the Rails world, models are only used with > databases. I don''t have a database involved. I just want to pass a > common value from the controller to the views and I don''t want to have > to redundantly specify that value in each of the actions. > > Thanks for the input. > > ... doug > > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
> In that case would an @variable in before_filter, rather than an instance > variable do?I''m sorry. I''m not following. I thought an @variable was an instance variable. As I see it, in order to implement your suggestion, I need to do something like: before_filter do |controller| The_meat_goes_here end I don''t know what to put where I have, "The_meat_goes_here". ... doug
On Apr 28, 9:30 am, djolley <ddjol...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > In that case would an @variable in before_filter, rather than an instance > > variable do? > > I''m sorry. I''m not following. I thought an @variable was an instance > variable. >it is.> As I see it, in order to implement your suggestion, I need to do > something like: > > before_filter do |controller| > The_meat_goes_here > end >you don''t want to use that form of before filter (you''d be setting instance variables on the wrong object). you want something like before_filter :setup_stuff ... protected def setup_stuff ... end As for what goes inside setup_stuff, that''s up to you. If what you want to do is set instance variables you can do it in there. Fred> I don''t know what to put where I have, "The_meat_goes_here". > > ... doug
Freddy Andersen wrote:> Is this something that you can do with a before_filter?I looked up filters, and the description I read says a filter applies to only one action. That would mean the op would have to write the same before filter for every action. Or is there a way to refer to the same filter? Colin Law wrote:> I am having difficulty imagining why you would want an > instance variable of a controller that is not associated with > an action...That does not summarize what the op wants to do--quite the opposite. The op wants one instance variable to be associated with *every* action. For instance, in a ruby class you can do this: class A def initialize(val) @var1 = val end ... end Then @var1 will be accessible inside any method in class A. Also, if you write: class A def meth(val2) @var2 = val2 end and then you call meth(), then @var2 will be created and it too will be accessible inside any method in class A. If rails worked the same way as ruby, then any instance variable defined in one action would be accessible inside any another action--which would also mean that all the views associated with all the actions could also access the instance variable. Instance variables are really just global variables within a scope: the class scope. Like global variables, instance variables can be accessed anywhere inside their scope. Rails seems to be saying, "No global variables". But in this case, that rule is causing the op to "get wet" by having to write something like: @var1 = 10 in every action. If the op wants to change that constant at some later date, then it means changing it in every action (which really isn''t that bad--search and replace in one file), but that isn''t DRY.>> Are you sure it is not an instance variable of a model that you should >> be using? > > I don''t think so. Models extend from ActiveRecord::Base. Therefore > in my nieve view of the Rails world, models are only used with > databases.Not true, not true. I''m reading AWDWR(3rd), which is very highly regarded in the rails world, and in their first non trivial example they create a model that is not hooked up to a database. They just navigate to the models directory, open up a blank file, and define a class which does not inherit from anything. Voila, a new model. In my naive view, a model is any class that has methods that do something. The way I look at it is, the controller is very lazy--instead of calculating or doing stuff itself, it would rather call methods in other classes so that they have to do the work. A model that is hooked up to a database provides easy database access for the controller. But other models have methods that do other things, and when the controller needs to get those other things done, it calls the methods in those models.> they I don''t have a database involved. I just want to pass a > common value from the controller to the views and I don''t want to have > to redundantly specify that value in each of the actions.Creating a model that is not hooked up to a database sounds like something that might work. It could be as simple as: class Constants attr_reader :val def initialize @const = 10 end end Then in an action, you could write: c = Constants.new val = c.const Of course, then you have to write that in every action--but if you ever want to change the value of the constant, you only have to change it in one place: in the Constants class. -- Posted via http://www.ruby-forum.com/.
7stud -- wrote:> Doug Jolley wrote: >> Values of instance variables set within an action of a controller are >> available in the template associated with that action. I was thinking >> (hoping?) that the values of instance variables set within a >> controller but outside of any action would be universally available to >> all the templates associated with that controller. Apparently that is >> not the case. Two questions: (1) Why is that? > > Perhaps a more basic question is: why is the template able to access the > private variables in the controller at all?Well, I fooled around and answered my own question. This is a toy example that I came up with (the output, variable names, and the comments make it self explanatory): class A def initialize @var1 = 10 @var2 = 20 end def meth @greeting = "hello" end end a = A.new p A.new.instance_variables --output:-- ["@var1", "@var2"] a.meth #>creates another instance variable(see definition of meth) names = a.instance_variables p names --output:-- ["@var1", "@greeting", "@var2"] names.each do |name| print "#{name} = " val = a.instance_variable_get(name) print val puts end puts --output:-- @var1 = 10 @greeting = hello @var2 = 20 class B end b = B.new #>Now attempt to insert the instance variables from obj a into object b: names.each do |var_name| #>names contains a''s instance var names from above var_val = a.instance_variable_get(var_name) b.instance_variable_set(var_name, var_val) #>Now if you inspect b: #> p b #>the output will be: #> #<B:0x2420c @var1=10> #>If you look closely, you can see @var1 in there #>along with its value. However, @var1 ends up being a #>private variable and it is inaccessible: #> puts b.var1 #>results in an error message. So... B.class_eval("attr_reader :#{var_name[1..-1]}") #>I want to insert the statement: #> attr_reader :var1 #>into class B. The variable var_name is assigned a #>string like "@var1", so var_name[1..-1] is equal to #>"var1". Remember arrays and strings are indexed #>starting at 0, also an index of -1 is the last character #>in the string, so some_string[1..-1] returns the substring #>starting at position 1 and ending at the last character-- #>in other words some_string[1..-1] is a copy of some_string #>with the first character chopped off. So if var_name is #>equal to "@var1" the string: #> "attr_reader :#{var_name[1..-1]}" #>is converted to: #> "attr_reader :var1" #>which is the string I am after. After that string is #>eval''ed in class B, I should have access to the #>private variable @var1. end puts b.var1, b.var2, b.greeting #>Will it work? --output:-- 10 20 hello Great success! Robert Walker wrote:> Rails does some magic to make that happen. Here is a blog post > that explains the basics of how this happens: > > http://www.neeraj.name/blog/articles/719-how-controller-and-view-share-instance-variablesIn the linked article, there is an extra step: a''s var names and values are stored in a hash. That is easy to incorporate: a_names_vals = {} #<---added **** names.each do |name| print "#{name} = " name_symbol = name.to_s val = a.instance_variable_get(name_symbol) print val puts a_names_vals[name_symbol] = val #<---added *** end puts p a_names_vals #<---added *** --output:-- {"@var1"=>10, "@var2"=>20, "@greeting"=>"hello"} class B end b = B.new #>Then this simplifies down to: a_names_vals.each do |var_name, var_val| b.instance_variable_set(var_name, var_val) B.class_eval("attr_reader :#{var_name[1..-1]}") end puts b.var1, b.var2, b.greeting --output:-- 10 20 hello -- Posted via http://www.ruby-forum.com/.
7stud -- wrote:> Robert Walker wrote: >> Rails does some magic to make that happen. Here is a blog post >> that explains the basics of how this happens: >> >> http://www.neeraj.name/blog/articles/719-how-controller-and-view-share-instance-variables > > In the linked article, there is an extra step: a''s var names and values > are stored in a hash. That is easy to incorporate: > > a_names_vals = {} #<---added **** > > names.each do |name| > print "#{name} = " > name_symbol = name.to_s > val = a.instance_variable_get(name_symbol) > print val > puts > > a_names_vals[name_symbol] = val #<---added *** > end > puts > > p a_names_vals #<---added *** > > --output:-- > {"@var1"=>10, "@var2"=>20, "@greeting"=>"hello"} > > > class B > end > > b = B.new > > #>Then this simplifies down to: > > a_names_vals.each do |var_name, var_val| > b.instance_variable_set(var_name, var_val) > B.class_eval("attr_reader :#{var_name[1..-1]}") > end > > puts b.var1, b.var2, b.greeting > > --output:-- > 10 > 20 > helloDarn, I forgot to incorporate some changes I made before posting that second part (namely astring.to_s doesn''t do anything): class A def initialize @var1 = 10 @var2 = 20 end def meth @greeting = "hello" end end a = A.new a.meth a_names_vals = {} names = a.instance_variables names.each do |name| val = a.instance_variable_get(name) a_names_vals[name] = val end p a_names_vals --output:-- {"@var1"=>10, "@var2"=>20, "@greeting"=>"hello"} class B end b = B.new a_names_vals.each do |var_name, var_val| b.instance_variable_set(var_name, var_val) B.class_eval("attr_reader :#{var_name[1..-1]}") end puts b.var1, b.var2, b.greeting --output:-- 10 20 hello -- Posted via http://www.ruby-forum.com/.
On Apr 28, 9:35 am, 7stud -- <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Freddy Andersen wrote: > > Is this something that you can do with a before_filter? > > I looked up filters, and the description I read says a filter applies to > only one action. That would mean the op would have to write the same > before filter for every action. Or is there a way to refer to the same > filter?That''s not true. By default a filter applies to all actions. You can change that with the :only and :except options.> > Then @var1 will be accessible inside any method in class A. Also, if > you write: > > class A > def meth(val2) > @var2 = val2 > end > > and then you call meth(), then @var2 will be created and it too will be > accessible inside any method in class A. If rails worked the same way > as ruby, then any instance variable defined in one action would be > accessible inside any another action--which would also mean that all the > views associated with all the actions could also access the instance > variable.rails is ruby. different web requests are handled by new instances of controllers though, so if you set a controller instance variable it won''t be there on the next request. At a basic level, before_filter :meth is pretty much the same as just calling meth at the top of every action, without the repetitiveness.> Of course, then you have to write that in every action--but if you ever > want to change the value of the constant, you only have to change it in > one place: in the Constants class. >You could also create an actual constant, eg class Person MINIMUM_AGE = 18 end and then use Person::MINIMUM_AGE Fred> -- > Posted viahttp://www.ruby-forum.com/.
Frederick Cheung wrote:> On Apr 28, 9:35�am, 7stud -- <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote: >> Freddy Andersen wrote: >> > Is this something that you can do with a before_filter? >> >> I looked up filters, and the description I read says a filter applies to >> only one action. �That would mean the op would have to write the same >> before filter for every action. �Or is there a way to refer to the same >> filter? > > That''s not true. By default a filter applies to all actions. You can > change that with the :only and :except options. >Ah, yes. I should have read more carefully>> accessible inside any method in class A. �If rails worked the same way >> as ruby, then any instance variable defined in one action would be >> accessible inside any another action--which would also mean that all the >> views associated with all the actions could also access the instance >> variable. > > rails is ruby. different web requests are handled by new instances of > controllers though, so if you set a controller instance variable it > won''t be there on the next request. >Ok, that makes sense.> At a basic level, before_filter :meth is pretty much the same as just > calling meth at the top of every action, without the repetitiveness. >Yes. I tested out a before filter, and it seems like a simple way to provide a controller wide "global variable" that the views can access. In my case, I used the before filter to set the value of an instance variable for the new and edit CRUD actions, and then both views used the instance variable as the default value for a text field. Simple solution. So what''s all the fuss about??>> Of course, then you have to write that in every action--but if you ever >> want to change the value of the constant, you only have to change it in >> one place: in the Constants class. >> > You could also create an actual constant, eg > > class Person > MINIMUM_AGE = 18 > end > > and then use Person::MINIMUM_AGE >Yes, I know. Thanks. -- Posted via http://www.ruby-forum.com/.
Frederick Cheung wrote:>> If rails worked the same way >> as ruby, then any instance variable defined in one action would be >> accessible inside any another action--which would also mean that all the >> views associated with all the actions could also access the instance >> variable. > > rails is ruby. different web requests are handled by new instances of > controllers though, so if you set a controller instance variable it > won''t be there on the next request. >I had been thinking along those lines, and I meant to test the following but I got sidetracked: class ProductsController < ApplicationController # GET /links # GET /links.xml def initialize @val = 10 super end and that seems to work as well. All the views for the actions in the ProductsController gain access to the @val instance variable. Is overriding the super class''s initialize method bad form in rails? -- Posted via http://www.ruby-forum.com/.
On Apr 28, 11:38 am, 7stud -- <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> class ProductsController < ApplicationController > # GET /links > # GET /links.xml > > def initialize > @val = 10 > super > end > > and that seems to work as well. All the views for the actions in the > ProductsController gain access to the @val instance variable. Is > overriding the super class''s initialize method bad form in rails? >you could do that. i would usually prefer before_filters (at least in part because you only have one initialize method so you''d have to chuck everything in there, whereas you can have separate, appropriately named before filters that setup related collections of variables. Fred> -- > Posted viahttp://www.ruby-forum.com/.
So to sum it up is is as simple as this: class MyController < ApplicationController before_filter :setup_stuff ... protected def setup_stuff @var1 = ... @var2 = ... end end then @var1 and @var2 will be available in views for all actions of MyController Colin 2009/4/28 Frederick Cheung <frederick.cheung-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>> > > > On Apr 28, 11:38 am, 7stud -- <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> > wrote: > > > class ProductsController < ApplicationController > > # GET /links > > # GET /links.xml > > > > def initialize > > @val = 10 > > super > > end > > > > and that seems to work as well. All the views for the actions in the > > ProductsController gain access to the @val instance variable. Is > > overriding the super class''s initialize method bad form in rails? > > > you could do that. i would usually prefer before_filters (at least in > part because you only have one initialize method so you''d have to > chuck everything in there, whereas you can have separate, > appropriately named before filters that setup related collections of > variables. > > Fred > > -- > > Posted viahttp://www.ruby-forum.com/. > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
So, I see that we have a working solution to this problem. THAT''S GREAT NEWS! Thanks a batch for all of the contributions. I would, however, like to see if the solution couldn''t be advanced one step further. The methodology that we have working so far is to define a method as a filter somewhere and then pass the name of that method as a symbol to before_filter. Obviously, this requires a separate definition of the method. My question is this: Can we somehow do this whole thing in a single step by passing the before_filter a block rather than a symbol? before_filter is supposed to accept a block. So, conceptually, my understanding is that we would need some code that looks something like this: before_filter do |controller| some_code_here end Can anyone please tell me what code I would need to supply as a replacement for some_code_here in order to get this thing to work using a block. Thanks. ... doug
On Apr 28, 4:58 pm, djolley <ddjol...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> before_filter a block rather than a symbol? before_filter is supposed > to accept a block. So, conceptually, my understanding is that we > would need some code that looks something like this: > > before_filter do |controller| > some_code_here > end > > Can anyone please tell me what code I would need to supply as a > replacement for some_code_here in order to get this thing to work > using a block.A key difference with using the block form is that (because blocks are closures) self will be the class, not the controller instance (which is why you get passed the controller as a parameter). For example you can''t do before_filter do |controller| @val = true end because that will set the instance variable in the wrong object. you could use controller.instance_variable_set but that''s just disgusting. so you''re left with before_filter do |controller| controller.some_method end ... def some_method end at which point you might as well do before_filter :some_method. Plus I like giving things names when appropriate. Fred
> because that will set the instance variable in the wrong object. you > could use controller.instance_variable_set but that''s just disgusting.Well now, hold on there a minute, Fred. :) I kind of like it. In fact, it''s exactly what I asked for. I don''t find it all that disgusting. Anyway, I now know how to do it both ways and I can decide which way I like the better. Thanks to all for the input in this topic. ... doug
Hi djolley. You can also use class variables or global variables: test.rb: $b=''global value'' class MyTest @@a=''class value'' def class_val @@a end def global_val $b end end test = MyTest.new puts test.class_val puts test.global_val $ ruby test.rb class value global value These variables will not be reset when a new instance is created. Haven''t tested @@class_val in a view but it should work. Regards, Morgan djolley wrote:>> because that will set the instance variable in the wrong object. you >> could use controller.instance_variable_set but that''s just disgusting. >> > > Well now, hold on there a minute, Fred. :) I kind of like it. In > fact, it''s exactly what I asked for. I don''t find it all that > disgusting. Anyway, I now know how to do it both ways and I can > decide which way I like the better. Thanks to all for the input in > this topic. > > ... doug > > > >
Morgan Christiansson wrote:> Hi djolley. You can also use class variables or global variables: > > test.rb: > > $b=''global value'' > class MyTest > @@a=''class value'' > def class_val > @@a > end > def global_val > $b > end > end >BAD RUBY!! No global vars! Don''t even go there. That''s all I have to say about that. :-) -- Posted via http://www.ruby-forum.com/.
Doug Jolley wrote:>> because that will set the instance variable in the wrong object. you >> could use controller.instance_variable_set but that''s just disgusting. > > Well now, hold on there a minute, Fred. :) I kind of like it. In > fact, it''s exactly what I asked for. I don''t find it all that > disgusting. Anyway, I now know how to do it both ways and I can > decide which way I like the better. Thanks to all for the input in > this topic. > > ... dougIf you want to be a good Rails citizen, I''d recommend following Fred''s advice. He have you a clean and conventional solution and I guarantee you he knows what he''s talking about. I''d have given you the same advice if the original posting was stated slightly more clearly. -- Posted via http://www.ruby-forum.com/.