Undefined method when creating a helper in Rails - ruby-on-rails

I tried to create a helper module to be able to set the title of a page. Of course it's not working (reference) Is there something I must define in a controller for my helpers methods to be seen by my controllers??
Gitlink: works_controller.rb
def index
set_title("Morning Harwood")
#works = Work.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #works}
end
end
In application_helper.rb:
module ApplicationHelper
def set_title(title = "Default title")
content_for :title, title
end
end
In the layout work.html.erb:
<%= content_for?(:title) ? content_for(:title) : 'This is a default title' %>

Helpers in Rails are methods available in views (and controllers if you include them) that allow you to avoid code repetition in views.
An example of a helper from my code is a method that renders html for facebook login button. This button is in reality more than user sees, because it's a hidden form with some additional information, etc. For this reason I wanted to make a helper method out of it, so instead of copying 10 lines of code multiple times I can call a single method. This is more DRY.
Now, back to your example, you want to do two things
display page <title>,
add <h1> header at the top of the page.
I see now where linked answer wasn't clear enough. You indeed need helper, but you also need to call it! So
# application_helper.rb
def set_title(title = "Default title")
content_for :title, title
end
# some_controller.rb
helper :application
def index
set_title("Morning Harwood")
end
And then in layout's views you can use:
<title> <%= content_for?(:title) ? content_for(:title) : 'This is a default title' %><</title>
...
<h1><%= content_for?(:title) ? content_for(:title) : 'This is a default title' %></h1>

Related

How to use Rails caches_action with layout:false and dynamically change meta tags?

I am stuck at what I think is a very simple/common usecase in a Rails web application. I want to use "caches_action, layout:false" and display, from the layout, dynamic tags that will be set by the action (either from the view or the controller).
I could not find any standard rails way to do this as content_for does not work with caches_action, instance variables are not cached (?), and the metatags helper gems that I have tried (metamagic and meta-tags) do not support this usecase.
Is there any way to do this ?
Example
I am using caches_action, layout:false on a SandboxController#show method
#app/controllers/sandbox_controller.rb
class SandboxController < ApplicationController
caches_action :show, layout: false, expires_in: 1.minute
def show
#meta_title = "Best page ever"
do_some_expensive_operation
end
end
The view
#app/views/sandbox/show.html.erb
We are in show action.
The layout
#app/views/layouts/application.html.erb
<title><%= #meta_title %></title>
Debug: <%= #meta_title %> <br/>
<%= yield %>
Thanks !
I found a way to make it work, it's not as pretty as I would like it to be but it helps using caches_action and setting HTML meta tags from the view.
Also, for the record, it seems that this was forgotten and buried deep down in the pipeline, as I did not find any recent mentions of this problem, only that caches_action and content_for together are not expected to work.
Solution: I simply add a before_action to set the meta tags by using as less computation as possible.
#app/controllers/sandbox_controller.rb
class SandboxController < ApplicationController
caches_action :show, layout: false, expires_in: 1.minute
before_action :seo_show, only: :show
def seo_show
#meta_title = "Best page ever"
end
def show
do_some_expensive_operation
end
end
It's worth noting that it can be used in combination with metamagic gem too.
Layout:
#app/views/layouts/application.html.erb
<%= default_meta_tags && metamagic %>
<%= yield %>
And helper:
#app/helpers/application_helper.rb
module ApplicationHelper
def default_meta_tags
meta title: #meta_title || "Default meta-title of my website"
end
end
Hope this helps someone out there !

can view not extend "application/application.html.erb" in ruby on rails?

As we all know, in ruby on rails, all views extends from application/application.html.erb, most of the time this is great, such as the application.html.erb as follow:
<html>
<head></head>
<body>
<%= render 'layouts/header' %>
<%= yield %>
</body>
</html>
I do not need the write the same code in every view again, but sometimes, just on view is special, this view is different from the view, such as I do not want to add <%= render 'layouts/header' %> in this view.
Maybe a parameter will just help me in this situation, but I want to know if any view is able to not extend from application/application.html.erb?
Views don't 'extend from' application.html.erb, they use it as a default layout. You can change it, of course, using layout method in controller (or layout option in render method), like this:
# this changes the default layout in every views of `AdminController` (and all other controllers that inherit from `AdminController`):
class AdminController < ApplicationController
layout :admin
# ...
end
# this changes the layout of specific action:
class SomethingController < ApplicationController
# ...
def some_action
# ...
render layout: :some_layout
end
end
Here's the reference:
http://guides.rubyonrails.org/layouts_and_rendering.html

Getting 'form_for(#something)' to work outside of new.html.erb

I want to place my <%= form_for(#something) do |f| %> which is currently located in app/views/something/new.html -- inside multiple pages, so maybe in app/views/layouts/application.html.erb
How do I get the #something variable and the form to work properly there, or somewhere else -- since it's defined in the controller #new action of SomethingController, it only seems to be available in the appropriate new.html.erb view..
You can put the form anywhere, just provide an instance variable of #something in controller
The basic usage is here.
ThisThingsController
def show
#this_thing = foo
#that_thing = bar
end
end
# View
<%= #this_thing %>
<%= form_for #that_thing %>
Of course you can use partial to render the form, as long as you feed it with variable it needs.
Try
<%= form_for SomeThing.new do |f| %>
Without fully understanding what you are trying to accomplish, I'll make this suggestion.
Add a before filter to your ApplicationController (alternatively you could create a module and mix it in where needed). Then call the before_filter when needed. This example will always run the before filter:
class ApplicationController
before_filter :set_something
private
def set_something
#something = ... # Fill in the logic here
end
end
Then add your form where needed. You can even make it appear conditionally depending on whether #something is set.
<% if #something %>
# Form goes here
<% end %>

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

Rendering different views in one action

I want to have 2 kinds of views for the same posts in my rails application. For instance - in one where a logged in user can update and edit the post, and in the other any user can just view it and comment on it or select it.
How should I go about this? Do I need a separate class? I know I need a separate view for each, but how about the model and the controller?
1.case: your views are going to have similar content, but only the signed in users will have extra options like editing.
You should use a partial view and in your main view you should write something like this:
<% if signed_in? %>
<%= render 'edit_form' %>
<% end %>
Remember, the name of the partial should always start with a underscore, so your partial in this case would be called _edit_form.html.erb or _edit_form.html.haml, depending on what you are using.
2.case: depending on if the user is signed in or not, you want to render completely different views, then you should handle it in your controller:
def show
if signed_in?
render 'show_with_edit'
else
render 'show_without_edit`
end
end
And your files would be named show_with_edit.html.erb and show_without_edit.html.erb
Also, if your view for a signed in user was called show then you could just do this:
def show
render 'show_without_edit' unless signed_in?
end
3.case: if you want to change basically EVERYTHING depending if the user is signed in or not, you could create some custom methods and call them inside your original action like this:
def show
if singed_in?
show_signed_in
else
show_not_signed_in
end
end
private
def show_signed_in
# declaring some instance variables to use in the view..
render 'some_view'
end
def show_not_signed_in
# declaring some other instance variables to use in the view..
render 'some_other_view'
end

Resources