Rails - multiple views for one controller - ruby-on-rails

I would like to give my application 2 different views (HTML, CSS, JS):
for an unauthorized user (nice looking one)
only for an authorized user (raw tables with all model data and
its available actions buttons)
and make possible for the authorized user to switch between them.
As for now I have 2nd and I'm going to create user authorization (probably with CanCan gem) and then 1st.
guides.rubyonrails.org "2.2.12.2 Choosing Layouts at Runtime" describes nice way to switch between layouts but it's not enough for me I think.
In my case both layouts would look the same or almost the same:
<!DOCTYPE html>
<html>
<head>
# layout depended JS and CSS maybe
</head>
<body class="container">
<%= render 'layouts/navbar' %>
<%= render 'layouts/flash' %>
<%= yield %>
</body>
</html>
What I'm interested in is to decide somehow which folder will be used to fill yield above.
I have slides_controller.rb and /app/views/slides/* and I would like to create one more, let say /app/views/slides_nice/* and use same slides_controller to decide which one should be used for rendering.

I think what you need is to authenticate in controller and give different template to render.
such as (assuming there is current_user helper from devise or your own authentication solusion):
if current_user
render "template_1"
else
render "template_2"
Also CanCan is currently outdated as R Bates no longer updating it. It does not work with new rails releases. And i'm not sure if role based authorization is what you want, you seems just want to hide something from guest users.

Related

Display selection of index in a partial

I've been trying to solve the following challenge all day without any luck.
When going through forum posts I came across jQuery and AJAX which are both new concepts to me and which I'd rather skip for now, if possible.
I've got a partial, "navbar-left", which shows a list of all bank accounts in my model Account.
When the user clicks on one of the items in the list, all transactions of that account should be shown in the same page at the right. The partial below links to a new page which is not how I'd like it.
The navbar-partial:
<ul class="nav nav-pills nav-stacked">
<% #accounts.each do |account| %>
<li role="presentation"><%= link_to account.account_holder, account_mutations_path(account.id) %></li>
<% end %>
</ul>
Any tips on how to get this fixed is much appreciated!
The page with the navbar at the left
The mutations in a separate page instead of a partial
Either you're sending viewers to a new page, or dynamically loading content within their current page.
If the latter, then the only solution is AJAX.
Luckily, Ruby on Rails makes transitioning from one to the other very easy.
Here is a gist of how it works:
<%= link_to account.account_holder, account_mutations_path(account.id), remote: true %>
This was pointing back to some page previously (e.g. action.html.erb).
Because of remote: true, it's going to be sending JS directly to the browser instead of a new HTML page (e.g. action.js.erb in the same view folder and same action name).
Here we can control the behavior we want by rendering a partial using ERB and using JS to change the HTML content of some part of the page:
// action.js.erb
$('#some_element').html('<%= j render "partial" %>')
Which will insert the HTML of the partial directly into the JQuery that changes the content dynamically.
Where j is a shorthand for escape_javascript.
Without escaping, the Ruby output is interpreted as file output and newlines would break your JS.
Example JS output without escaping:
// Bad
$('#some_element').html('<span>Content</span>
<span>More Content</span>')
Example with escaping:
// Good
$('#some_element').html('<span>Content</span>\n<span>More Content</span>')
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
https://launchschool.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails
There are more great examples online and even Railscasts.
Really AJAX is the best way to do this, and it's not as complicated as you might think. But if you really want to skip AJAX then your best approach is probably to load ALL transactions for all accounts, in different div's and then show or hide them based on which is clicked.
For a rudimentary introduction to this look at javascript tabs... you click on a tab, the appropriate information is shown.
http://www.w3schools.com/howto/howto_js_tabs.asp
You can do this very simply without ajax. The big difference would be - it's not the same page. One page would be the account#index (as you have now), the other page is the account#show page.
For the show page, use a very similar view as the index page, the left side would include the partial with one of the account li class="active" to highlight the account you are currently on. For the right side of the page, render the account mutations list items.

Use template to create multi-page ruby on rails web application

Is there any way to create a webpage template that I will be applying to all my webpages?
I am new to ruby on rails, I have gained enough knowledge to understand how flow works in it but can't find out the way to use the same page-template for all pages on the site.
I am using RubyMine but can work on command prompt if required.
Any help would be greatly appreciated.
app/views/layout/application.html.erb this is a common layout in which you will found <%= yield %> which render all the pages in <body> tag. Now as per your requirement you want some common template to show on all pages.
So better to make one partial file..For example, Header and Footer remains same in whole site. For doing this, make one partial file called _header.html.erb for header part and _footer.html.erb for footer part. Put these files under app/views/layout/_your_partialfile.html.erb
Then render them like:
<%= render partial: "/layouts/header" %>
<%= yield %>
<%= render partial: "/layouts/footer" %>
For more info refer : http://guides.rubyonrails.org/layouts_and_rendering.html
I hope this makes you clear to understand now. :)
In general, rails projects have a file in app/layouts/application.html.haml that's applied to every single page you load. You can put navbars there, login links, etc.

How to avoid embedding javascript in views/show

I have a Rails app that uses javascript (Backbone) to show user specific data on each users profile page /views/users/show.html.erb. I do this by passing <%= #user.id %> as a data parameter to Backbone's fetch function, however, the only way I know how to get the <%= #user.id %> into Backbone's fetch function is by embedding the javascript in each views/users/show.html.erb page, which therefore allows Backbone to load different user specific info for each views/users/show.html.erb page. Although this works, it seems like the wrong way to do it, as I have read that I should not embed javascript like this. Furthermore, I am going to have to do it a lot, because I wish to display a lot of different kinds of data, more than you see below. So the show.html.erb page will be filled with javascript to make the app work the way I wish.
Question: how might I get #user.id into Backbone's fetch function for each user's show page without embedding javascript in the way that I've done. In the comments, someone suggest I use app/assets/javascripts/user.js, but I don't know how to get <%= #user.id %> into that file. #user.id is readily available in show.html.erb
<script type='text/javascript'>
$(document).ready(function() {
app.collections.awardCollection.fetch({ data: $.param({ user_id: <%= #user.id %> }) }).complete(function(){
app.views.awardCollection = new app.Views.awardCollection({ collection : app.collections.awardCollection});
app.views.awardCollection.render()
});
});
</script>
In order to understand how the views works, is that you can add as many extensions to a view as you want, and they will be parsed by the right library.
If you create a view like
my_view.haml.erb
It will be first parsed with ruby (erb), and then with haml, and will end in a html page.
You can create many views for js, usually you want to archive that when you do ajax, so you can end having a js view like:
my_view.js.erb
First ruby will be parsed (all the <% %> tags), that will end as plain text, and then the server will serve the .js file. But that's usually a common task for ajax.
If you have to render a html page where you want to put some js and you need some ruby code on it, what I usually do is to put the data in the html content with a hidden div.
You can put in any view (even on your layout if you want it to be globally available), something like:
<div id="user_id" style="display: none;"><%= #user.id %></div>
And then on a js (or coffeescript or whatever) you can just check the content of that div:
<script type="text/javascript">
var user_id = $("#user_id").html();
</div>
that's really useful when you want to debug or create tests for your js files, since its plain js and won't throw syntax errors.
I see the comment of Luís Ramalho and Gon is a good option, but I recommend use the following approaches:
If the from the variable is not going to change, print it with <%= %> under .js.erb files located in app/assets/javascripts (note that it will be cached until you restart your app)
If you need server variables the best way is to use Ajax
You can define functions on .js files on app/assets/javascripts and call those functions from the views
If you really don't want any Javascript code in the view, you can create the functions on a .js on app/assets/javascripts (corresponding to the view, for order), and use events and/or store the variables in hidden fields (or even use the data attribute from HTML5)

How do you handle widgets in rails?

StackOverflow, for example, has a user's reputation displayed up top. Clearly, this is grabbed from the database, and it's displayed on every page. Of course, this isn't in every controller action on every page, because that would be incredibly redundant.
How do you handle this kind of situation in rails? The only way I can think of it is to use before_filters to pass the models into the page, but that just seems like abuse of that feature. There seems to be the cells gem that does what I want, but I'd imagine this is a common problem and there must be a simple solution for it in rails without having to resort to plugins or gems.
What you are looking for is the layout. In rails this is where you define headers, footers, and sidebars that frame your site. Look for app/views/layouts/application.html.erb in your generated rails code. Towards the bottom you will see:
<body>
<%= yield %>
</body>
The yield is where rest of the app gets invoked. Everything before and after the yield will appear on every page. So, using your example, you might query the database and set the instance variable #reputation in the application controller:
#reputation = User.find( current_user ).reputation
then display it in the layout like this:
<body>
<%= #reputation %>
<%= yield %>
</body>
This is covered thoroughly in the book "Agile Web Development With Rails". If you are going to develop in Rails I recommend getting the latest edition.
I would just make a partial with the widget in it and render it in the layout(s) where you want it to appear. Let it do whatever it needs to do, eg connect to the db, run some js to connect to an external site, etc.
If you're concerned about optimisation then deal with it when it becomes a problem.
I guess, you can put the code you need into a view helper. And then render some partial, like it was said before, in the layouts where you want it to appear, calling helper's function.
Look here:
Rails view helpers in helper file

Rails + facebox + authlogic - how?

on my web site I want to have login/registration form in modal window done using facebox (jQuery plugin). What is better:
Create view with one method and template that has form and refer facebox to this view.
Create static HTML file in public directory and refer facebox to this static page.
What I want to achieve is:
Easy verification (like "user name already taken", "password confirmation doesn't match password" and stuff like that).
Easy submit and redirect
I'm new to Rails, I just know about forms verification in Django, so for Django I would probably choose option 1, but it might be another thing in Ruby.
If you want the verification to come back to the registration page, you should make it a dynamic page.
The other problem with a static page in the public directory is that your links all become hardcoded, so if you application ever lives off the domain root (i.e. example.com/app) the links in that static file could be wrong.
Additionally, if you ever need to move your images to a different host, you lose the advantages of the image_tag.
Only use static resources if you know things won't change and you need speed. If your dynamic pages are too slow, you can cache them, or you might be doing something wrong.
UPDATE: (to address the first comment)
You can't use the rails functions to build your URLs when you are in the public folder. If you need rails generated URLs in your javascript, trigger them from a rails view page.
Generally, I'll do the following:
In application.html.erb in the head tag:
<%= yield :headScripting %>
Then in the view page that is triggering the javascript:
<% content_for :headScripting do %>
jQuery().ready(function() {
jQuery("#placeholder").load("<%= summary_model_path(#model) %>");
});
<% end %>
That would load the summary text from the model controller action summary. This would probably render :text => "summary" or render :layout => false depending on your needs

Resources