Rails4 about helper_method - ruby-on-rails

I have question about helper_method.
When I add fuc in /controller/application_controller.rb
helper_method :values
def values
#food = Food.all
#food_type = FoodType.all
end
I want to use var on /layouts/application.html.erb
code here
<% #food.each do |fp|%>
<p><%= fp.name %></p>
<% end %>
<% #food_type.each do |ft|%>
<p><%= ft.name %></p>
<% end %>
but it return nill .
Please teach me ,thx a lot

You can try this
application_controller.rb
def values
#food = Food.all
#food_type = FoodType.all
[#food, #food_type]
end
application.html.erb
<%food, food_type = values%>
<% food.each do |fp|%>
<p><%= fp.name %></p>
<% end %>
<% food_type.each do |ft|%>
<p><%= ft.name %></p>
<% end %>

DRY
You'll be much better using the before_action callback
The problem you have is a helper is meant as a simple way to create functionality for your application. IE that you pass some data to the helper, it will "crunch" the data, and return a reasonable response.
This is why Vimsha's answer has been accepted - he has made it so that your helper method will return the values you need; consequently meaning you need to call the method if you want to use the data it has .
--
The real answer for you (considering you just want to be able to use the #food and #food_type variables in your application layout), is to use a callback which sets these variables each time:
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
before_action :set_vars
private
def set_vars
#food = Food.all
#food_type = FoodType.all
end
end
Although relatively inefficient (you'll be best caching this data so it won't be pinging your DB each time), you'll be able to use #food and #food_type in your application layout with no issues

Related

Rails Partials - conditionality with locals

I have the following code in a Rails partial being used in some mailers but am not happy with my solution and have the feeling this is far from optimal.
I have an email which
From my mailer:
def the_email_i_am_sending(user, inquiry, params = {})
get_variables(inquiry) #This also provides access to my `#user` object
#contact_name = [params[:guest_last_name].to_s, " ", params[:guest_first_name].to_s].join
I always have #user but on occasion a specific partner will call our API with additional params of [:guest_last_name] and [:guest_first_name] as defined above. This allows me to define #contact_name as a separate instance variable.
When this is .present? i.e. not nil, I want to render #contact_name in a field on the email rather than the #user.login that would pull from our DB.
My mailer view then uses the following code to decide which partial it will render.
<% if #contact_name.present? %>
<%= render 'meet_your_guest_v3', tujia_guest: #contact_name %>
<% else %>
<%= render 'meet_your_guest_v3' %>
<% end %>
My solution is then to utilise this code in the partial being rendered in the mailer. It seems a little verbose but I am unsure about the correct usage of local_assigns.has_key?
<% if local_assigns.has_key?(:partner_guest) %>
<%= partner_guest %> <p>(via our partner</p>
<% else %>
<%= #user.login %>
<% end %>
Is there a better way?
You should definitely follow the advice from #Jon regarding dealing with params in your controller/mailer. Additionally you should just pass #contact_name every time to the underlying partial, regardless if it is present or not, then check only where you want to render it, if it is present. This way you would skip one conditional:
#email_view.html.erb
render 'meet_your_guest_v3', parnter_guest: #contact_name
_contact_name.html.erb
<% partner_guest.present? %>
...
A further step could be using a special decorator object, which would deal with the presentation logick. It would check wether contact_name was provided from outside or from the model and render the desired html tag for the contact_name (or it could just return it as string). See following pseudocode using the draper gem:
class MyController < ApplicationController
def send_mail
#user = User.find(...).decorate(
contact_name: [params[:guest_last_name].to_s, " ", params[:guest_first_name].to_s].join
)
MyMailer.the_email_i_am_sending(#user)
end
end
class MyMailer < ApplicationMailer
def the_email_i_am_sending(user)
#user = user
mail(to: ..., subject: ...)
end
end
class UserDecorator < Draper::Decorator
def contact_name_tag
if (contact_name.present?)
h.content_tag(:div, contact_name)
else
h.content_tag(:div, user_name)
end
end
end
#email_view.html.erb
<%= #user.contact_name_tag %>
However if the presentation logic isn't very complicated, going with a couple conditionals and perhaps extracting them into basic rails helpers is fine and using a presenter may be an overkill

Using a controller variable in application html.erb

I'm probably trying too hard for my first website but i wanted to make a dropdown on a (bootstrap) navbar to be flexible, and show the names of the saved work categories.
This is what i've tried to do in the application.html.erb file :
<ul class="dropdown-menu">
<% #workcategory.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
Failed with error undefined methodeach' for nil:NilClasson the<% #workcategory.each do |workcategory| %>` line.
This is the workcategories controller :
class WorkcategoriesController < ApplicationController
before_action :find_workcategory, only: [:edit, :update, :destroy]
def index
#workcategories = Workcategory.all.order("created_at DESC")
end
def new
#workcategory = Workcategory.new
end
def create
#workcategory = Workcategory.new(post_params)
if #workcategory.save
flash[:notice] = "Workcategory created"
redirect_to(:action=>'index', :workcategory_id => #workcategory.id)
else
#workcategories = Workcategories.order()
render('new')
end
end
def edit
end
def update
end
def destroy
#workcategory.destroy
redirect_to workcategory_path
end
private
def find_workcategory
#workcategory=Workcategory.find(params[:id])
end
def post_params
params.require(:workcategory).permit(:name)
end
end
Any tips and help are welcome, even non-related to the initial question :) Thank you
If you want it in all ur actions, it is wise to put it in your application_controller.rb.
before_filter :set_work_categories
def set_work_categoriers
#w_categories = Workcategory.all.order("created_at DESC")
end
This should work fine.
Also, a tip.
You can use default_scope {order(created_at: :desc)} in your model WorkCategory.rb
Then you can use this like,
def set_work_categoriers
#w_categories = Workcategory.all
end
I would recommend changing the variable name to #w_categories or else it will conflict with your #work_categories name in index action.
In your application.html.erb file, change
<% unless #w_categories.nil? %>
<ul class="dropdown-menu">
<% #w_categories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
</ul>
<%end>
I guess this should do the trick
If we talk about index action, then you just forgot to use appropriate variable:
<ul class="dropdown-menu">
<% #workcategories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
Update
If you want to have this in all actions, then initialize #workcategories in before_action:
# your_controller.rb
before_action :initialize_work_categories
def initialize_work_categories
#workcategories = Workcategory.all.order("created_at DESC")
end
Layouts
application.html.erb is a layout, meaning that it will be present regardless of whether you're using the Workcategories controller or not.
If you want to load a variable into the layout, irrespective of which controller is being invoked, you'll need to make sure the #workcategory variable is present.
To do this, you would generally put the #workcategory declaration into the ApplicationController (which most other controllers inherit from):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_categories
private
def set_categories
#workcategory = ....
end
end
This is the standard way to populate layout-side variables. It's not efficient and only works if your controllers inherit from the Application controller.
Some further pointers would include the following:
1. Object orientation
Ruby, and by virtue, Rails, is object orientated.
This means that everything you do should revolve around objects. This is why Rails has many helpers that seem to work "magically".
They're not magic at all - they just take the objects you pass them, and build pre-baked HTML to give you specific functionality.
A good example are the routes:
#config/routes.rb
resources :controller
The reason this is important is that when you call actions / variables, you need to think of them as objects. This is difficult to do for newbies, but if you can get your head around it, it helps your coding massively.
--
2. Controllers
Following on from the above, you have to remember that your controller is really just a way to manipulate objects.
Thus, if you're calling #workcategory, you need to appreciate where the object is going to come from and how it's going to be populated.
You can make a helper method work_categories and use that. Either define it directly in application_helper - or if you don't want to use helpers you can put this code in your ApplicationController
class ApplicationController < ActionController::Base
def work_categories
Workcategory.all.order("created_at DESC")
end
helper_method :work_categories
end
Then in your view:
<ul class="dropdown-menu">
<% work_categories.each do |workcategory| %>
<li><%= workcategory.name%></li>
<% end %>
</ul>

Why my helpers does not outputting nothing in my view?

I'm new on rails and I have a book to study them. In one practice, I created a helper in my Application Helper, the test from RSpec work fine, until I have to print the result of my helper. No show any result and no error happens.
application_helper.rb
module ApplicationHelper
def title(*parts)
unless parts.empty?
content_for :title do
(parts << "Ticketee").join(" - ")
end
end
end
end
show.html.erb
<% title(#project.name) %>
projects_controller.rb
class ProjectsController < ApplicationController
def show
#project = Project.find(params[:id])
end
end
and when I go to the show link I supposed to see "Random Project name - Ticketee", however only they show me "Ticketee".
Any help...
<% title(#project.name) %>
Means don't show to the user
<%= title(#project.name) %>
Means show to the user - notice the equals.

Calling a method in the view controller Rails

To generalize my problem, I am using an API that returns an iterable object. Within that those is an id for each object. My controller looks like this:
class SearchController < ApplicationController
def index
#search = API.find(params[:query])
end
end
My view is something like this:
<% #search.each do |thing| %>
<h2><%= thing.attr2 if thing.attr1 %></h2>
<%= API.list(thing.attr2) %>
<% end %>
I have tried adding a method into
class SearchController < ApplicationController
def index
#search = API.find(params[:query])
def getList(attr2)
API.list(thing.attr2)
end
end
end
and adding index and self before the definition (ex: self.getList(attr2)) and calling it in all those variations in the view:
<%= getList(thing.attr2) %>
I am wondering where I am going wrong here. I have additionally tried to add in the helper_method line as I read in a few docs but it would not recognize it. Also, would this be the correct way to go about this style-wise? Having a hard time finding references for it makes me think this isn't standard practice.
The method I was trying to make is a helper method, and therefore, needs to go in the helper method for the controller.

Rails: Loading in array of partials

In my Rails app I already have the following code:
<% %w(number_of_students edit_class_name tech_help).each do |modal| %>
<%= render "common/modals/#{modal}" %>
<% end %>
There will be a few more modals added into app/views/common/modals and instead of explicitly listing them out in the %w() I was wanting to loop through the common/modals directory and just render each file.
Here is what I came up with:
def render_modals
files = Dir.glob("#{Rails.root}/app/views/common/modals/*").collect { |file| File.basename(file, ".html.erb").sub("_", "") }.flatten
files.collect do |modal|
render partial: "common/modals/#{modal}"
end.join.html_safe
end
define a simple method in where is more appropriate (maybe app helper?) like this:
def modals
%w(number_of_students edit_class_name tech_help)
end
if you need these modals in a controller/model too, maybe you should define this method in an appropriate class? For example
class Modal
def self.types
%w(number_of_students edit_class_name tech_help)
end
end
Also, if you are rendering the templates often, then also define
def render_modals
modals.map do |modal| # Modals here should be the method that you just defined, example, Modal.types
render partial: "common/modals/#{modal}"
end.join
end

Resources