Automatically generate html file from an erb file using Ruby on Rails - ruby-on-rails

I have a RoR app that tracks the status of values in a database and displays the visualization of this information in the form of charts, graphs, and tables generated by an erb file. This is very handy and I am able to save snapshots of the status' of the DBs by simply saving the page when I open it in a browser. What I would like, however, is for my app to automatically do this saving for me on a nightly basis. I assume this is possible but I'm not having much luck with this so far. Any suggestion on this point would be very helpful.

you can always use render_to_string method to render your erb. For example you need to render show.html.erb for show action in statistics controller:
my_page = render_to_string :controller => 'statistics', :action => 'show', :layout => 'application'
but firstly you should define all it's variables which you use int show view.
#data = Data.last_data
#users = User.active
enter code here
my_page = render_to_string :controller => 'statistics', :action => 'show', :layout => 'application'
snapshot = Snapshot.new :page => my_page
snapshot.save
API: http://apidock.com/rails/ActionController/Base/render_to_string

You can use whenever: https://github.com/javan/whenever
From the readme:
Whenever is a Ruby gem that provides a
clear syntax for writing and deploying
cron jobs.
There is also delayed-job: https://github.com/tobi/delayed_job
From the Readme:
Delayed_job (or DJ) encapsulates the
common pattern of asynchronously
executing longer tasks in the
background.

Related

How do I render a partial from the Rails console?

I'm using Rails 4.0.3. How do I render a partial from the Rails console?
Try this (in the console):
# initial setup
view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
av_helper = ActionView::Base.new view_paths
# (Optional) include this if your partial uses route helpers:
include Rails.application.routes.url_helpers
av_helper.render "path/to/your/partial"
Also, for templates:
av_helper.render :template => "path/to/your/template"
Update: The OP reported the partial rendering line did not work, and generated an error. I didn't encounter that, but if others do, this is the version the OP indicated was successful:
av_helper.render :partial => 'tags/tag', :collection => Tag.limit(3)
As Josh Diehl pointed out, you can also use the usual options like locals in the render. I would expect you should be able to use all the usual render options normally used in controllers and views.
Josh's example:
av_helper.render(partial: "tags/tag", locals: {term: term})
There is an official way to do this in Rails 5 (cf this pull request):
ApplicationController.render 'templates/name'
The developer also made a gem to support this in Rails 4: backport_new_renderer
For me the best way to get it working in Rails 4.2 was with this twoliner:
view = ActionView::Base.new('app/views/products', {}, ActionController::Base.new)
output = view.render(file: 'index.html', locals: {:#products => Product.all})
I found this solution on github.

Including a partial "as is" in Ruby on Rails

I am using stache for server-side evaluation of Mustache templates. I would like to re-use some of these templates on the client-side from JavaScript using ICanHaz.js, but to do so I need to include them into script tags. I would like to avoid duplicating the templates (DRY), but obviously, the templates must not be evaluated before being sent to the client, so using a simple render :partial invocation like in this (HAML) snippet does not work:
%script{:id => 'project_snippet'}
= render :partial => 'project'
Is there any way to include a partial without evaluating it using the underlying template engine (kind of like a raw include)?
In other places the partial is to be used as regular partial, i.e., evaluation is supposed to happen, so changing the file extension to always avoid evaluation is not an option.
do you need a partial as is or you want it to be rendered as HTML with some placeholders for JavaScript templating? you can pass :locals => { ... } with something to be replaced by JS template engine later i.e.
%script{:id => 'project_snippet'}
= render :partial => 'project', :locals => {:name => '{{{ project_name }}}'}
if as is then read the partial content (but it doesn't look like you want this)
%script{:id => 'project_snippet'}
= File.open("#{path/to}/partial.html.haml", "r").read
Well, it seems that I should have read the stache documentation: There is a tag helper available, so
= template_include_tag 'projects/project'
will do the trick after setting the template base directory in an initializer:
Stache.configure do |c|
c.template_base_path = "#{Rails.root}/app/views"
end

How to upgrade the :update=>'div_id' option of remote_form_for from Rails 2 to Rails 3?

I can't figure out how to upgrade this code from Rails 2 to Rails 3:
<% remote_form_for(item, :update => 'div_id') do |f| %>
...
I tried this:
<%= form_for :item, :remote => true, :url => { :controller => "items", :action => "create" }, :update => 'div_id' do |f| %>
...
It creates the new item but it fails in updating the content within <div id="div_id"></div> tags. It seems Rails 3 no longer supports the ":update" option for a remote form_for. Any suggestion?
You could use RJS, but that's being deprecated too (and for good reason). The simplified, best-practices way to handle this in Rails 3+ is as follows (assuming jQuery):
# your_view.html.erb
<div id="receiver-id"></div>
<%= form_for :some_model, :remote => true, :id => 'form-id' do |f| %>
...
<% end %>
# application.js (or any other .js loaded on the page)
$(function(){
$('#form-id').bind('ajax:success', function(xhr, data, status){
$('#receiver-id').html(data);
});
});
The ajax:success hook gets called by the jquery-ujs (aka jquery-rails, aka rails-ujs) remote link/form handler. See for yourself. There are lots of other callbacks/hooks available for you to use, too. If you wanted to make this even more flexible, you could use live instead of bind, and bind to a class that dictates where the ouput goes (e.g. "sidebar") and then all remote links/forms with the sidebar class would have their HTML response go to div#sidebar.
The most straightforward way to do this would be to write a javascript view template, e.g. create.js.erb which would look something like this:
$('#div_id').html("<%= escape_javascript(render(#item)) %>");
(depending on your setup, of course, I'm assuming an #item variable and an associated _item partial)
Edit:
coreyward is right. This is the RJS way which is more of the old fashioned Rails 2.x "Rails way". It's probably more familiar, but has issues. Your specific case is one of them, actually, as typically you might bind to an HTML element to update using the record's id (e.g. div #item_1), and in the create case there is no id available beforehand, complicating matters.
Binding via clientside JS eliminates this issue. RJS works in something of a vacuum, making assumptions about the state of the client's HTML and having no access to it.
I know the question is old but I when migrating to Rails 3 I found a pretty good way of doing this, so I thought I would post it here in case anyone else is in a similar solution.
In layouts/update_page.js.erb I put this file:
$j('#<%=#update_div_id||"list_div"%>').html('<%= escape_javascript render(:partial => (#partial_div||"index"), :locals => #local_hash) %>');
This is mainly used for searches that use remote, so in the index action in the controller, I just added the following code.
respond_to do |format|
format.html
format.js {render 'layouts/update_page'}
end
Since remote is being used, it will always try to use javascript first, so it will render the update_page.js.erb file from above. For us, we almost always use the div#list_div on our index pages, so we update that by the default, however if you need to update something different, you can pass in #update_div_id, and if you need to render a different page, you can pass in #partial_div.
To clarify, for a lot of things, it is probably better practice to use the callbacks, but I found this to be a much easier way, when we had to migrate over nearly 100 of these calls.

Generate PDF file using AJAX call

I'm trying to generate a PDF file using AJAX call in Rails3. The following code generates a PDF file which I have created using PRAWN gem.
<%= link_to "Generate pdf", books_path(#book, :format => 'pdf') %>
I do not want user to view the PDF until they order it. So, the goal is to create a PDF file in the server.
Any ideas or thoughts much appreciated.
Use this, make sure your remote action does not return the PDF, but simple generates and stores it on the server.
link_to "Generate PDF", prepare_books_path(#book), :remote => true, :method => :put
This will work in Rails 3. If you're using jQuery, make sure to read this article on how to set things up correctly.
Your controller action may look like this:
def prepare
# Do your thing to generate the PDF
render :text => "PDF Generated", :status => 200
end
I used the PUT-method because you are altering the state of your data (e.g. you are generating something new, you don't want a bot or crawler to automatically call that).
Firstly, it beats me why you would do something on a request like generating a PDF, when the user is not expecting that action. Isn't better to only generate the pdf when the user requests for it?
Thanks Ariejan.
I modified your code as following and it did just what I wanted.
<%= link_to "Generate Story Book", pdfbook_stories_path(:format => 'pdf'), :remote => true %>
And for the controller,
def pdfbook
#stories = current_account.stories
respond_to do |format|
format.pdf {}
end
end

Partial not updated on first click

I am having problems with a remotely executed action and a partial that doesn't update the first time I click the link.
Inside the view (a partial named books) I am creating a link:
link_to "⊗", read_book_path(book), :remote => true
The read_book_path is defined in routes.rb
There is also a conditional that displays a different text when that book is read.
Inside my controller, I have defined a new action:
def read
#books = Book.all
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
respond_to do |format|
format.html { redirect_to(books_url) }
format.js {render :layout => false, :locals => { :book => #book } }
end
end
This means I need a file read.js.erb, this file's content is:
$("#books").empty().html("<%= escape_javascript( render(:partial => "books") ) %>");
When I click the link, I can see in the terminal window that the database field is updated but the partial is not. Clicking the same link again updates the partial.
Changing the link to :remote => false also works but the page reloads (as expected).
I have tried to debug it with Safari and the Developer tools and I can see the server's response when clicking the link for the first time.
Something is wrong there, the HTML generated by <%= escape_javascript( render(:partial => "books") ) %> contains the wrong HTML with the old content of the partial. Only the second or third click shows the updated HTML.
I have integrated jquery-ujs - is that the reason the partial doesn't update the first time or am I missing something else?
This really gave me a headache, can you help me?
Edit:
If that helps: I created a listener in application.js to ajax:before and ajax:complete. The first one shows a little spinner, the second one hides it.
When I click the link, the spinner shows but it doesn't hide.
It looks like you have an ordering problem that's causing the trouble. You're capturing a complete set of books into the #books variable and then modifying a separate copy of a single book. This change will not be propagated back.
# Load and modify the one book by flipping the flag
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
# Load all books
#books = Book.all
As a note this is an extremely inefficient way of doing things, so I hope you're not working on a large amount of data. You might find it's easier to do this by simply toggling the one field with a simple UPDATE query:
Book.update_all({ :read => true }, { :id => params[:id] })
I'm not sure why you're calling $(...).empty().html(...) instead of simply $(...).html(...) since the html() method should replace the HTML wholesale with no need to clear it in advance.
One thing that might help is using .js.rjs where the equivalent would be:
page[:books].replace_html(:partial => 'books')
With simple JavaScript, RJS allows you to eliminate a lot of the drudgery. You can use JS in RJS as well for cases where there is no equivalent:
page << '$("#books").empty()'
page[:books].replace_html(:partial => 'books')
To make this more Rails friendly, you could call your partial _book which would make the local variables redundant. Each partial has a default variable with a name matching the template name:
render(:partial => 'book', :collection => #books)

Resources