Variable scope in child template view in ERB - ruby-on-rails

I'm trying to declare defaults in my layout that can be overridden in the view.
This is my layout:
<%# Variables defaults -%>
<%
#cssFiles = []
#jsFiles = []
-%>
<%# Variables overrides -%>
<%= yield :layoutVariables -%>
And my view:
<% content_for :layoutVariables do -%>
<%
#cssFiles.push 'bootstrap'
#jsFiles.push 'bootstrap'
-%>
<% end -%>
I know this can be done by declaring the variables in the controller but I'd like to know whether the scope can extend from layout->view.

As I see you are trying to collect some assets files inside the view. It is not very good option.
I recommend to make new module
config/initializers/frontend.rb:
Module Frontend
##fe = Array.new()
def self.getfe
##fe
end
def self.add_css(css)
##fe << css
end
end
And now you can simply add your css file anywhere to this array just simply call:
Frontend::add_css "yourfile"
And get your array back simply call
Frontend::getfe
This mechanism with class methods works in views also
Good luck!

Related

FormBuilder helper method with block capture not working in ERB

I have a custom FormBuilder that has a group method that acts as a wrapper around each label/input/hint/error combo. The group method itself is very simple, but when I try to use it from ERB like I would with "fields_for" or similar, it does not render properly.
def group(**options, &)
options[:class] = class_names(options[:class] || "flex flex-col mt-4", options.delete(:classes))
content_tag(:div, capture(&), **options)
end
In the ViewComponent that is using the form helper I can do the following just fine
def call
#form.group(**#group) do
concat #form.label(:tags, #label.delete(:text), **#label)
concat #form.text_field(:tags, **#system_arguments)
end
end
But if I try to write that in an ERB partial, it either does not render the wrapper from group at all, or it only renders the text_field and not the label
<%= #form.group(**#group) do %>
<%= #form.label(:tags, #label.delete(:text), **#label) %>
<%= #form.text_field(:tags, **#system_arguments) %>
<% end %>
Not sure what I'm missing to get the ERB version to work properly...
There is a fix, but it's not released yet:
https://github.com/ViewComponent/view_component/pull/1650
# Gemfile
gem "view_component", github: "ViewComponent/view_component"
# config/application.rb
config.view_component.capture_compatibility_patch_enabled = true
https://viewcomponent.org/known_issues.html#compatibility-with-rails-form-helpers

Rendering rails partial with dynamic variables

I'm trying to render a partial based on the taxon the user is inside. In my application.html.erb layout I have the following line of code:
<%= render 'spree/shared/women_subnav' if #enable_women %>
In the taxons controller, inside the show method, I have:
#taxon_id = params[:id].split('/').first
And in taxons#show I have:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" = true %>
<% end %>
When I run this I get a SyntaxError. But in taxons#show If I just enter:
<% if #taxon_id == params[:id].split('/').first %>
<%= "#enable_#{#taxon_id}" %>
<% end %>
without the '= true' then the page renders, outputting '#enable_women'. So I know it's getting the correct variable, I just need that variable to be set to true. What am I missing?
Thanks so much.
First of all I would like to give you some heads-up:
calling first on a user submittable input is not a great idea (what if I submit ?id=, it would return nil) also non utf-8 encoding will crash your app such as: ?id=Ж
Controllers are beast! I see you are setting the value of a true/false instance_variable in the view, please use controllers do define the logic before rendering its output. especially when parameter dependant.
so for a solution:
in your controller as params[:id] should suggest an INT(11) value:
def action
# returning a Taxon should be a good idea here
#taxon = Taxon.find(params[:id])
# as I would give a Taxon class an has_many relation to a User
#users = #taxon.users
end
and in your action's view
<%= render :partial => "taxons/users", collection: #users %>
of course you would have the great ability to scope the users returned and render the wanted partial accordingly.
if you want more info about "The Rails way" please read:
http://guides.rubyonrails.org/
Have fun!
use instance_variable_set
instance_variable_set "#enable_#{#taxon_id}", true
just a reminder that it's better to do these things inside a controller.

Debug output in all views

I'm currently developing a new Rails 3 app. All my instance variables defined in the controllers will automatically be debugged in my views. This happens both in development and production mode.
As much as this is helpful, I'd really like to get rid of that because it destroys the HTML layout partially.
For example I have in my controllers index actions:
respond_with(#articles = Article.published.order("created_at DESC").page(params[:page]).per(5))
In the view you will automatically see something similiar like the output of <%= debug #articles %>, although I never call inspect or debug in my views.
A sample picture to demonstrate the whole issue:
http://www.diigo.com/item/image/16wox/padm?size=o
My Gemfile looks like this: https://gist.github.com/1080104
You should create a method in your application helper module:
def debug_all &block
excluded_vars = ["#lookup_context", "#view_context_class", "#action_has_layout"]
controller.instance_variables.each do |var|
unless var.at(1)== "_" or excluded_vars.include?(var)
yield var
end
end
end
And in your application layout:
<% debug_all do |var| %>
<%= "variable name: #{var} " %>
<%= eval(var).inspect %>
<% end %>

ruby on rails global method

I have a user controller which consists of a method named listfolders().
class UserController < ApplicationController
def myaccount()
userId = session[:id]
#listfolders = UsersFolders.listfolders(userId)
#users = User.listusers()
end
end
In the views I have and I'm able to fetch the folders:
<% #listfolders.each do |userfolder| %>
<tr>
<td><b><%= userfolder.foldername %></b></td>
</tr>
<% end %>
PROBLEM: I want to display the folders in all pages like compose,drafs,trash etc ... instead of just for the action.
How can I do it ?
The basic, standard way to do this would be in a helper.
module ApplicationHelper
def listfolders(user_id)
lf = UsersFolders.listfolders(user_id)
render 'users_folders/listfolders', :listfolders => lf
end
end
then in app/views/users_folders/_listfolders.html.erb
<% listfolders.each do |userfolder| %>
<tr>
<td><b><%= userfolder.foldername %></b></td>
</tr>
<% end %>
calling it is as easy as:
<% listfolders(session[:id]) %>
If I understand everything right you need some :before_filter in your controller to initialize #listfolders and #users variables
You can easily move the code to load the folder + the partial template to a cell component and then call that cell from any view.
Check this:
http://cells.rubyforge.org/
It will work just like the render :partial calls but will add a controller like process that should load the user folders and then will create the partial to be rendered.
The other approach that should work is to have a method on the application_controller to load the folders. Then add a before_filter calling that method to every action that should render the folders.
Finally you can create a shared partial to be rendered on each of the views that should be showing that.
Note: The method to load the folders can be defined in a more specific controller if you will only show the folders on actions from the same controller of for a child controller.

Confused on Advanced Rails Layout Nesting

I currently have a few layouts that my application uses (the ... is identical between all layouts):
# application.html.erb
...
<div id="section"><div class="wrapper"><%= yield %></div></div>
...
# wide.html.erb
...
<div id="section" class="wide"><div class="container-12"><%= yield %></div></div>
...
# thin.html.erb
...
<div id="section" class="thin"><div class="container-06"><%= yield %></div></div>
...
I am looking to re-factor the code to reduce duplication, however the strange placement of the class variables (outside the yield) makes it difficult. Should I be using variables for declaring the class values within my layout (and move to a single layout) or should I be adding container.html.erb layout that contains the duplicate ... then render the three other layouts from it (or does another third option exist that I am missing)? I'm looking for the "Rails" way to do it if possible. Thanks!
module ApplicationHelper
def section_helper(outer_class=nil,inner_class)
content_tag(:div, :class=> outer_class, :id => :section) do
content_tag(:div, :class=> inner_class) do
yield
end
end
end
end
and in the layouts:
<%= section_helper("wrapper") { yield } %>
<%= section_helper("wide","container-12") { yield } %>
<%= section_helper("thin","container-06") { yield } %>
This works nicely for the first case where there is no "outer" class, since :class => nil renders nothing. But you could also pass in a hash if having an optional first argument is confusing.
We've done something like this using an instance variable like #sectionclass. Then we set it to a default in the ApplicationController and flip it to page specific values in other controllers. Then your page would be something like this:
<div id="section" class="<%= #sectionclass %>"><div class="container-12"><%= yield %></div></div>
The nice part of the instance variable is that the nil case fails silently with an empty string. (Albeit some may say this is 'bad').

Resources