Properly rendering multiple layouts per controller in Rails - layout

I've defined in my Users_controller:
layout "intro", only: [:new, :create]
Here's what my layout looks like:
Intro.html.haml
!!! 5
%html{lang:"en"}
%head
%title Intro
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body{style:"margin: 0"}
%header
= yield
%footer= debug(params)
When I render a page that calls for intro as the layout, it gets nested inside my application.html.haml file which is not good.
Is there some way of avoiding this undesirable nesting of layouts?
Thanks in advance!

The problem was in my Controller. I was declaring multiple layout instances like so:
class UsersController < ApplicationController
layout "intro", only: [:new, :create]
layout "full_page", only: [:show]
...
end
Don't do this! The second declaration will take precedence and you won't get your desired affect.
Instead, if your layouts are simply action-specific, just declare it within the action like this:
def show
...
render layout: "full_page"
end
Or, if it's a bit more complex, you can use a symbol to defer the processing to a method at runtime like this:
class UsersController < ApplicationController
layout :determine_layout
...
private
def determine_layout
#current_user.admin? ? "admin" : "normal"
end
end

Related

Generate Wagtail Field's using a FOR loop

I am new to Wagtail and want to create several Field's in my models.py by iterating over a list of names like this ...
class HomePage(Page):
myFields = [ ('paragraph', blocks.RichTextBlock(classname="oneA")),('image', ImageChooserBlock()) ]
mySections = ['sectionOne', 'sectionTwo', 'sectionThree']
for mySection in mySections:
mySection = StreamField(myFields,null=True,blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('sectionOne'), StreamFieldPanel('sectionTwo'), StreamFieldPanel('sectionThree'),
]
This produces an error message ...
django.core.exceptions.FieldDoesNotExist: HomePage has no field named 'sectionOne'
Is there a way of doing this, or do I have to declare each one individually like so:
sectionOne = StreamField(myFields,null=True,blank=True)
This doesn't work because mySection = StreamField(...) is just repeatedly defining a field called mySection - there's no way for Python to know that you want to define a field with the name currently given in mySection.
I think the only way to achieve this is to set the fields up in a metaclass, which will almost certainly be more complex and less readable than just repeating the line. See How to dynamically set attributes to a class in models in Django?, Dynamically create class attributes

Rubymotion Teacup variable scope

Following the Tweets example of Teacup, I'm trying to access a variable outside of the layout block
class WindowController < TeacupWindowController
stylesheet :pref_window
layout do
#loginButton = subview(
NSButton, :loginButton,
state: NSOffState,
buttonType: NSSwitchButton,
action: 'login',
target: self,
)
puts #loginButton.class
end
puts #loginButton.class
the first puts returns NSButton class, but the second one returns Nil class.
how can I access #loginButton if I need to programmatically make changes to it?
For example:
#loginButton.setState(NSOnState)
doesn't work outside the layout block.
You can use an attr_accessor on the WindowController, then in the layout block you can use self.loginButton and it will be assigned on the WindowController giving you access to the button.
I'm also assuming the second puts is actually in another method and this is just example code.
class WindowController < TeacupWindowController
stylesheet :pref_window
attr_accessor :loginButton
layout do
self.loginButton = subview(
NSButton, :loginButton,
state: NSOffState,
buttonType: NSSwitchButton,
action: 'login',
target: self,
)
puts self.loginButton.class
end
puts self.loginButton.class
end

How do I find all elements which have a css class in coded ui?

I need to find all Html controls which have a given css class.
var htmlControl = new HtmlControl(document);
htmlControl.SearchProperties[HtmlControl.PropertyNames.Class] = #class;
var uiTestControlCollection = htmlControl.FindMatchingControls();
Using the class name works when there is just one css class on the control. If I have more than one css classes applied on the element, can I search for the element by specifying just one css class and not all of them?
Thanks
You can perform a partial match, like so:
htmlControl.SearchProperties.Add(HtmlControl.PropertyNames.Class, #class, PropertyExpressionOperator.Contains);
var uiTestControlCollection = htmlControl.FindMatchingControls();
The main draw back of this is that it is just a simple string compare. To illustrate, imagine you have two controls A and B. A has class "Test" and B has classes "testdiv topnav". Now if you perform a search for "test", both controls A and B will be selected.
To match a class exactly, you can provide a close as match as possible using the above method and write a helper function to:
Loop through the collection
Get the class of each control
Split the class string on the spaces
Loop through this array and test each for an exact match
Keep the elements where a class matches exactly
Note: This is clearly non-optimal - I'm all ears if someone has a better solution.
Cheers,
Seb

how to use a controller variable in my layout

I am trying to use a variable of my controller in my layout.
For example:
#posts = Post.all.count
In my layout I want to list the Post count, even when I open the index view of another controller.
Many thanks!!!
Two solutions:
Use <%= Post.all.count %> in your layout.
Add a before_filter in your ApplicationController that loads the variable.
class ApplicationController < ActionController::Base
before_filter :load_layout_variables
protected
def load_layout_variables
#posts = Post.all.count
end
end

Rails3 get current layout name inside view

I have the answer for the Rails 2.X but not for Rails 3. How can I read the name of a current layout rendered inside a view.
My Rails2 question: Rails Layout name inside view
Thx.
Getting this to work in Rails 3.2 is a little more complicated than previously outlined. If your controller explicitly declares a layout, then the result of controller.send(:_layout) is a String, but otherwise it's an ActionView::Template. Try this:
module ApplicationHelper
def current_layout
layout = controller.send(:_layout)
if layout.instance_of? String
layout
else
File.basename(layout.identifier).split('.').first
end
end
end
in rails 5
This works for me:
def current_layout
layout = controller.class.send(:_layout)
if layout.nil?
default_layout
elsif layout.instance_of? String or layout.instance_of? Symbol
layout
else
File.basename(layout.identifier).split('.').first
end
end
For Rails 4:
controller.send(:_layout)
=> 'application'
For Rails 3.2:
controller.send(:_layout)
=> #<ActionView::Template:0x000000082bb788>
But controller.send(:_layout).identifier returns the fullpath:
/home/davidm/Documentos/Devel/myapp/app/views/layouts/application.haml
I think it should be in core, but for now you can make a helper method:
def current_layout
controller.send :_layout
end
it will return currently used layout name
I have used in Rails4 at view pages and got reuslt.
controller.send(:_layout)
I hope this help.
For rails 5:
controller.class.send(:_layout)
This does NOT work:
controller.send(:_layout)
You can do what I've done in my Ajax gem for Rails which is to wrap the _render_layout method:
ActionView::Base.class_eval do
def _render_layout_with_tracking(layout, locals, &block)
controller.instance_variable_set(:#_rendered_layout, layout)
_render_layout_without_tracking(layout, locals, &block)
end
alias_method_chain :_render_layout, :tracking
end
Then you can access the value that was set from your view (I'm pretty sure you have access to the controller there...) or in your controller in an after_filter, which is what I do.
I've written a custom RSpec 2 matcher which can be used to test layout rendering in Rails 3.
All the approaches in the previous answers try to guess the name via private methods, but there's no need to guess and can be easily accomplished with the public API:
class ApplicationController
layout :set_layout
attr_reader :layout_name
helper_method :layout_name
private
def set_layout
#layout_name = "application"
end
end
Override in any controller that won't use the standard layout:
class MyController < ApplicationController
private
def set_layout
#layout_name = "my_layout"
end
end
And now in your views:
<%= layout_name %>

Resources