How to build Help based on Markdown in Ruby on Rails 5? - ruby-on-rails

I am willing to create Help manual pages using Markdown files within my Rails application. I am already using Markdown for limited elements in some pages, but I now want to create dynamic pages using MD files. Searching around, I found some tips, but no complete HowTo.
My main issue was generating the route to various pages based on the requested MarkDown file. I propose the solution below, which fits well for documenting my application, and also allows contributors to easily enrich or translate the documentation.

Writing this question, I found the solution.
Here is what I did:
1 - I created a hierarchy of folders in public for supporting several languages. Each folder contains a help_index.md file, which contains links to other MD files:
public
help-en
help-index.md
logging.md
user-ceation.md
help-fr
help-index.md
logging.md
etc.
2 - I created a route (routes.rb) to reach these pages based on the page name:
# get '/help',
get 'help/*page_name', :controller => 'help', :action => 'help', :as => :help
3 - I created a link from the application header (application.html.erb):
<%= link_to t('Help'), help_path("help_index") %>
4 - I created a template for the help pages:
<% provide(:title, t('Help')) %>
<h1>Help pages</h1>
<p>
<%= displayHelp %>
</p>
5 - I created a controller (help_controller.rb) for displaying the page:
class HelpController < ApplicationController
def help
end
end
6 - I created a helper (application_helper.rb) for interpreting Markdown based on Redcarpet gem:
module ApplicationHelper
def markdown
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, :autolink => true, :space_after_headers => true)
end
def displayHelp
filename = File.join(Rails.root, 'public', "help-#{I18n.locale.to_s}", "#{params[:page_name]}.md")
begin
file = File.open(filename, "rb")
markdown.render(file.read).html_safe
rescue Errno::ENOENT
render :file => "public/404.html", :status => 404
end
end
end
And it works fine!

Related

Link_to in Rails. Link to displayed customized

I have an application, that takes a path of a file from the database and renders it to html and displays. The controller, view and routes look like the following:
project/index.html.erb
<p><%= link_to project.title,{:controller => "markdowns" , :action => 'view', :github_link=>project.github_link},:target=>"_blank"%></p>
markdown_controller
class MarkdownsController < ApplicationController
def view
#markdown=MarkdownsHelper.markdown path
end
def path
File.open(Rails.public_path.to_s+params[:github_link].to_s, "rb").read
end
end
MarkdownsHelper.markdown method in the above controller renders the .md.
markdown/view
<%=raw #markdown %>
routes
resources :projects
match '/GitRepos/'=>'markdowns#view'
The problem:
The link that is being displayed after clicking on the title in the prokects/index is localhost:3000/GitRepos?github_link=%2FGitRepos%2Fbootstrap%2FREADME.md
But I want the link to be displayed as localhost:3000/GitRepos/bootstrap/Readme.md
where bootstrap is Project.title and Readme.md is the file that is being read. Also, my Project database has a github_link attribute which stores GitRepos/bootstrap/Readme.md
Model
The link will change according to the project.
The Project model has these attributes-> title and github_link.
So there are many projects and github_link stores the path addresses of Readme.md file of each project located in the local system.
My Approach
Here is the solution which I have, with my minimal knowledge in Ruby on Rails. Please let me know if can improve on this.
project/index.html.erb
<p><%= link_to project.title,{:controller => "markdowns" , :action => 'view',:title=>project.git_name,:id=>project.git_file},:target=>"_blank" %></p>
routes
match 'GitRepos/:title/:id' =>'markdowns#view'
Try
match '/GitRepos/:github_link'=>'markdowns#view'

Argument error for file uploading with rails 3.1 app

I'm trying to set up a very basic system for uploading files to my rails 3.1 app. Before people start throwing paperclip and carrierwave links at me, let me say that this is NOT the solution that I am looking for. I have read quiet a few posts on this topic, however, all the code I saw was either depreciated in rails 3.1 or I just did not understand how people came to a solution to this problem.
Updated view/form: (haml)
%h1 File Upload
= form_for :upload,:url=>{:action => 'uploadFile'},:html => { :multipart => true } do |f|
%p
%label{:for => "upload_file"} Select File
\:
\#{f.file_field 'datafile'}
= f.submit "Upload"
Updated controller:
class UploadController < ApplicationController
def index
render :file => 'upload/uploadfile.haml'
end
def uploadFile
file_param = params[:upload][:datafile]
post = DataFile.save(file_param)
render :text => "File has been uploaded successfully"
end
end
Updated model
class DataFile < ActiveRecord::Base
def self.save(upload)
# Changed Default Destination: [__RAILS_DIR__/public/data]
name = "public/data/" + upload.original_filename
# can haz data directory?
require 'FileUtils'
FileUtils.mkdir_p(File.dirname(name))
File.open(name, "wb") { |f| f.write(upload.read) }
end
end
The Solution:
Above is the correct code I used to add simple uploading functionality to my rails 3.1 app
You are passing unnecessary argument "file" to the uploadFile method. It's an action and passing argument to it is not possible. Just remove the "file" argument.

How do I create a temp file and write to it then allow users to download it?

I'm working on my first application and I need some help with allowing my users to download a text file with certain variables that are being displayed on the page.
Take a shopping list for example.
Let's say you allow your users to create a shopping list of products, and then display the shopping list with the items on a shopping list page,
e.g. localhost:3000/list/my-list
Take a look at the example code below (which is probably incorrect):
File.open('shopping_list.txt', 'w') do |file|
file.puts 'Item 1: #{product_1.name}'
file.puts 'Item 2: #{product_2.name}'
file.puts 'Item 3: #{product_3.name}'
end
Which then creates a text file that has the following content:
Item 1: Eggs
Item 2: Butter
Item 3: Bread
Users should then be able to download this file (i don't want this file to be stored on the server) via a download link.
I have no idea how to achieve this, but I'm hoping you guys can guide me. :D
TL;DR
create text files populated with model data (perhaps create a method to achieve this?)
text files should not be stored on the server, but created as users click the download button (not sure if this is the rails way but perhaps someone could show me a better way)
I am assuming there is a resource for List with the attribute name as the name of the list and a list has_many Item which has an attribute description
First off, create a download path change your routes config/routes.rb
resources :lists do
member {get "download"}
end
Now if you run a rake routes in the console you should see a route like
/lists/:id/download
Whats more you should now have the helpers download_list_url & download_list_path to use in your view like
<ul>
<% #lists.each do |list| %>
<li> <%= list.name %> - <%= link_to 'Download List', download_list_path(list) %> </li>
<% end %>
</ul>
In your lists_controller add the action, and as you dont actually want to keep the file on the server disk just stream the data as a string
def download
list = List.find(params[:id])
send_data list.as_file,
:filename => "#{list.name}.txt",
:type => "text/plain"
end
Finally you see I have used a as_file method which you should add to the model (I prefer not to do this stuff in controllers, fat models, skinny controllers). So in the List model
def as_file
output = [self.name]
self.items.each {|item| output << item.description }
output.join("\n")
end
You say you don't want to store the file on the server, but "download" it on request; this sounds like you just want to generate and deliver a text document in response to the download link. There are several approaches, but you want to be sure of setting the mime-type so the browser sees it as a text file instead of an html document.
product_info = [
"Item 1: #{product_1.name}",
"Item 2: #{product_2.name}",
"Item 3: #{product_3.name}",
].join("\n")
render :text => product_info # implies :content_type => Mime::Type["text/plain"]
BTW, your example with open/puts above won't output what you think since single-quoted strings don't interpolate.
so, you wish to :
create text files populated with model data (perhaps create a method
to achieve this?)
text files should not be stored on the server, but
created as users click the download button (not sure if this is the
rails way but perhaps someone could show me a better way)
You have the right idea, here's what to do :
Create a method in your model to generate the text file contents. Let's say this method is called list_data
It seems like you have an existing controller action called my_list. Hence we can call our new method in the controller like so :
.
def my_list
# pre-existing code
respond_to do |format|
format.html # show html page as before
format.text do
send_data #list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
end
end
end
To link to the download, just use link_to :action => my_list, :format => 'text'
See http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data for full docs on send_data
Caveat & explanations : Using the method above, there isn't really an explicit creation of files, Rails is streaming it for you. Hence this method is not suitable for very large files, or when the generation of the file content will take a while. Use a delayed method to generate the file and store it - the file contents somewhere if that's the case - but we can use send_data once it has been generated
You could try a combination of TempFile and send_file. In your controller action ..
file = Tempfile.new('foo')
file.write("hello world")
file.close
send_file file.path
At Rails 2.3 you can use Template Streaming. Working with Redmine I can remember something like that, you have to adapt for your case. Reference: Streaming and file downloads
require "prawn"
class ClientsController < ApplicationController
# Generate a PDF document with information on the client and return it.
# The user will get the PDF as a file download.
def download_pdf
client = Client.find(params[:id])
send_data(generate_pdf, :filename => "#{client.name}.pdf", :type => "application/pdf")
end
private
def generate_pdf(client)
Prawn::Document.new do
text client.name, :align => :center
text "Address: #{client.address}"
text "Email: #{client.email}"
end.render
end
end
Using the Thong Kuah you must just change the "content_type" param:
def my_list
# pre-existing code
respond_to do |format|
format.html # show html page as before
format.text do
send_data #list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
end
end
end

How to create an atom feed in Rails 3?

I'm trying to set up a simple atom feed from my Posts model and I'm running into translation problems between rails 2 and rails 3.
I tried to accomplish this task with two steps:
Added the <%= auto_discovery_link_tag(:atom) %> to my /views/layouts/application.html.erb file.
Created a /views/posts/index.atom.builder file. The file contains:
atom_feed do |feed|
feed.title("Daily Deal")
feed.updated(#posts.first.created_at)
#posts.each do |post|
feed.entry(post) do |entry|
entry.title(post.title)
entry.content(post.body, :type => 'html')
entry.author { |author| author.name("Justin Zollars")}
end
end
end
I see the RSS link in my browser, but the link opens with an error:
Too many redirects occurred trying to open
“feed:http://localhost:3000/posts”.
This might occur if you open a page
that is redirected to open another
page which then is redirected to open
the original page.
Where have I gone wrong?
Try specifying a path to the feed:
<%= auto_discovery_link_tag(:atom, posts_path(:atom)) %>
Maybe you need to specify the actual feed address?
auto_discovery_link_tag :atom, "http://mysite.com/posts.atom"
If you're using FeedBurner, you'll want to use that address instead.
Also, do you have some kind of before_filter blocking the access to that page?

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

Resources