How to render different show templates conditionally - ruby-on-rails

I have got a Post model, and a post can be either a Video post (with YouTube link) or an Article post (with body text).
There is an enum post_type that determines the type of Post.
In my show.html.erb view I would like to display a different template file depending on the type of post displayed.
The entire html.erb file content is different for Articles and Videos.
In my controller I want to be able to check the post type and render a differnt file accordingly.
if #post.video?
//render video show view `video_show.html.erb`
else
// render article show view `article_show.html.erb`
end
I've already tried render template: 'posts/video' to render a new posts/video.html.erb file I created but that did not work at all.
What is the best way to do this? I want to follow convention and not use crude partials and a simple if-else to switch between partials.

Just simple render works for you, you can use below code:
Just render with HTML file name if file is in same controller's view
if #post.video?
render 'video_show'
else
render 'artical_show'
end

render works with just the relative file name
if #post.video?
# with a file name posts/video_show.html.erb
render 'posts/video_show'
else
# with a file name posts/article_show.html.erb
render 'posts/article_show'
end

Related

How does ActionView::Template :render decide where to load from?

Here's the problem, let's say I have a few resources that I want index all on the same page separated by tabs, in this case it's different types of content: videos, pdfs, etc. I also have a partial that gets included into several different views, in this case a search functionality. The partial does something like this to let you customize various parts of it:
in _search.html.slim:
.toolbar
.left
= render 'left_toolbar', f: f
The project tree looks something like:
app
--views
----media
------index.html.slim
------videos_list.html.slim
------pdfs_list.html.slim
------videos
--------_left_toolbar.html.slim
------pdfs
--------_left_toolbar.html.slim
And I have a controller that manages requests coming in from the page with the various content-resources:
in media_library_controller.rb:
def index
end
def videos
<sets everything needed to render a videos list, #videos etc.>
render :index
end
def pdfs
<sets everything needed to render a pdf list, #pdfs etc.>
render :index
end
And in the index.html.slim
= render 'application/search'
ul.nav.nav-tabs
li.active
a href='#videosListTab' data-toggle='tab' Videos
li
a href='#pdfsListTab' data-toggle='tab' PDFs
ul.tab-content
li.tab-pane.active#videosListTab
.js-video-collection
= render 'videos_list' if #videos
li.tab-pane.active#pdfsListTab
.js-pdf-collection
= render 'pdfs_list' if #pdfs
What I want is to be able to define in the controller which folder left_toolbar.html.slim is looked for when search.html.slim goes to look for it
I have tried overriding controller_path which doesn't seem to work. prepend_view_path seems promising but it appends the controller name to the end of the view path so that I have something like app/views/media_library/videos/media_library when I set it. Any advice? I don't want to had a local to the search partial.
What I want is to be able to define in the controller which folder left_toolbar.html.slim is looked for when search.html.slim goes to look for it
Perhaps you're getting ahead of yourself:
<%= render "shared/menu" %>
That code will pull in the partial from
app/views/shared/_menu.html.erb.
From what I understand of your question, you want to know how Rails can specify a specific path for your partial? There's no need - partials can be referenced from anywhere in your app.
So when you mention that search.html goes looking for it, you just have to prepend the folder for left_toolbar to the path:
render 'your_path/left_toolbar', f: f
Again, with your media tabs... they're all partials - just use the folder name in the partial path:
= render 'app/views/media_library/pdfs_list' if #pdfs

ruby code is showing as html in template

I have a rails app which uses angularjs. Here I'm trying to render a template from rails controller and pass a resource to the template. But the ruby code for displaying the variables are showing exactly as it is in the html.erb view.
def fail
#order = Order.find(1)
render 'payments/fail'
end
in view
<%= #order.as_json %>
My guess would be that the problem is in the name of your view file. I'd guess that you named it something like fail.html instead of fail.html.erb. Without the .erb suffix, Rails just interprets the file as html text and renders it without interpreting the ruby code.
However, changing the file name isn't quite the correct solution. Since you want to render json instead of HTML you don't need to create a view template, so you should just delete the template file altogether.
All Rails models have an .as_json method automatically, so you can simply modify your controller's fail method like so:
def fail
#order = Order.find(1)
render json: #order.as_json
end
Also if you want to do something fancy and modify the json that is returned, you can define your own as_json method inside the model.

Show top posts in a proper way Rails

I have a method in my posts_controller to display most viewed posts.
def top
#posts = Post.all.order("post.views DESC").page(params[:page]).per(10)
end
In routes I have
resources :posts do
collection do
get :top
end
end
The problem is: when i go to /posts/top i have an error: Missing template posts/top, application/top Do I need to write view files for my every method (top isn't the only one) or I can somehow display them in my index file without duplication of code?
Just render the index template at the end of your method:
def top
#posts = Post.all.order("post.views DESC").page(params[:page]).per(10)
render :index
end
I would suggest you to have a close look to rails layouts and rendering documentation. You will get your answer as well concept behind them. Below is the snippet of doc.
In most cases, the ActionController::Base#render method does the heavy lifting of rendering your application's content for use by a browser. There are a variety of ways to customize the behavior of render. You can render the default view for a Rails template, or a specific template, or a file, or inline code, or nothing at all. You can render text, JSON, or XML. You can specify the content type or HTTP status of the rendered response as well.

Render parial on certain action

Probably a newbie question, but when my user visits job#index I want to show a partial that is stored in my views/layouts called _subnav.html.erb.
This only needs to render when the user is at jobs#index.
Can someone help me with this but also understand how it works.
I'd suggest you use content blocks.
Within your layout file, such as layout/application.haml, place this code where you want the subnav to be rendered:
= content_for :subnav
..and within your view file (jobs/index.haml)
- content_for :subnav
= render partial: 'layouts/subnav'
Couple of alternatives:
Check controller#action in layout file and only show for jobs#index
Add a simple #show_sub_nav instance variable and set to true within your controller. In your layout file: = render partial: 'layouts/subnav' if #show_sub_nav
You can see how to achieve (2) with my answer here.

How can I load a embedded ruby javascript file on pageload?

So, as I am sure you are all familiar with, you can have actions in Rails that call html.erb files. You can also set up actions to render remotely that call embedded ruby files (for example submitting a "post" form to the "posts" controller, handling it remotely, and calling a js.erb file to update elements in the page).
What I want to know is how to run a js.erb file when I'm running an action that loads a template (html.erb file). To explain, consider if I want to run a User Show page:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
end
Linking to user_path(User.find(1)) will load show.html.erb, and all seems great.
But what if I want to click on a link to user_path(User.find(1)) and load show.html.erb while also loading show.js.erb? If (and I hope it is) this is possible, how could I adapt the show definition to also load show.html.erb and custom_js_file_name.js.erb?
FYI: I'm using Rails 3.0.9 and 3.1.3 on two different applications, and assume that I would put show.js.erb or any others in the Users folder (views/users/...)
By default,
def show
#user = User.find(params[:id])
end
will only render the show view based on if it was requested via HTML, JSON, JS, etc.
I think what you are describing is better suited for the render method in Rails. Typically, controllers use the different format.(:format) methods in the respond blocks to respond to a controller call based on what the request type was (JSON, HTML, JS, etc).
In your show.html.erb file:
<%= render "users/show.js" %>
This allows you to render any arbitrary file you want in another one of your views. This also allows you to split up your large view files into smaller (reusable) pieces called partials (note: all partials are named with a _ character at the beginning and are called via <%= render :partial => "users/my_partial" %> which would render the _my_partial.some_format.erb file)
Try having the show action render the show.js.erb file when requested with a format of js. That should get Rails to render the dynamic template; now link to it from the original show.html.erb with a javascript link tag.
In show.html.erb:
<script type="text/javascript" src="<%= show_users_path(#user.id) -%>.js"></script>
I haven't tried this and the rendering of show.js.erb may put additional formatting that would be a problem.

Resources