Embedded Ruby not being read when calling html_safe - ruby-on-rails

I'm developing a simple app that teaches people english. The app is based on 5 modules of 34 classes each - 170 total. Each class has its own html page.
Since i dont want to create a view for each class, i scaffolded an Aula model ("class" in portuguese) and saved the html of each class in the model's DB, so i could use only the standard Show view paths to show the classes using their individual id's.
Controller code:
def show
#aula = set_aula
end
These HTML pages are being stored in the database as strings and then being outputted on the Show view using the html_safe method.
#show view code:
<%= #aula.aula.html_safe %>
#"aula" is the DB attribute with the html of each class
It rendered the HTML with no problems, and i got what i wanted. But since i'm creating a rails app, i decided to use embedded Ruby code like <%= link_to %> and <% image_tag %> mixed with the HTML of the classes to create links and show images, and the problem is that these links are being outputted as strings as well, just like any other line, instead of being read and executed as actual Ruby code.
I've been doing a lot of research, but so far I can't find exactly how to make the ERB code be read properly.
Maybe I need to save the HTML in the DB using another data type, or I need to use another method to render the HTML.

First, I'll answer your question, then make a suggestion that you think very carefully before using this approach.
The answer in the post https://stackoverflow.com/a/14351129/483133 shows how to render ERB directly from stored HTML text. Modifying this, here is some code you could use:
def show_html
html = #aula.aula
template = ERB.new(html)
template.result.html_safe
end
# Run this from your controller action, for example, with
def show
#aula = set_aula
end
# inside your view show.erb.html
<%= show_html %>
Warning
I would strongly recommend against finding a solution that allows Ruby code stored in the database to be run. If the pages are able to be written in any way by end users, rather than trusted software developers, then you have opened a huge security hole. Any Ruby code could be run on your server.
I would suggest you consider using a client-side rendering solution (such as Handlebars: http://handlebarsjs.com/ ), which allows for basic rendering of data dynamically in HTML, while not allowing code to be run on your server.

Related

Confused about how the render works in rails

I'm still fairly new to rails, but I've been trying to figure it out by building a bunch of simple projects like blogs, forums, clones over the weekend.
One of the blogs that I'm working on is a typical blog with users(devise), posts, and comments. I've been following a tutorial for this.
The thing that I've been really confuse on is setting up the comments and rendering it.
The tutorial teaches me to make a partial for comment in the comment view named _comment.html.erb and then another for form _form.html.erb . I fully understand that to call the form i just do render 'comments/form' but for the comment.html.erb i need to render #post.comments how come it's not 'comments/comment'? Why is it comments with the S?
I've tried reading up on render and plurization on rails, but most of them just talk about the model.
There are two convention over configuration things going on here that may be causing you some confusion but are meant to save time.
Rails will automagically find the right partial if it follows naming conventions, meaning if your model is Comment that the view partial is located in app/views/comments/_comment.html.erb. That means you don't have to specify the location of the partial when calling render, but instead can just pass the model object directly and Rails figures out that you want it to render the partial and finds it on its own.
The reason it's comments plural here is that you are rendering all of the comments as a collection, not just a single comment. It's a convenience feature to allow the developer to simply tell Rails to render a collection and it will automagically know to use the corresponding partial. It's identical to typing:
#post.comments.each do |comment|
render 'comments/comment`, object: comment
end
Note how the above code is calling render directly on a model object so we don't have to bother specifying the location of the partial (again, assuming you followed the convention when naming and locating things). If we named the partial something else, then we'd have to specify the location like your other examples.

where to place my forms to follow 'DRY'

I am working on a larger application and I see that I end up repeating the same forms twice etc.
For example when you register and on edit account one is in the #new and the other is in the #edit. I'm assuming this is bad practice and it also takes up a lot of space in the view. How do I gather these forms and then just display them on both pages?
If you use the rails generators they normally create a structure like so:
edit.html.erb
new.html.erb
_form.html.erb
Both new and edit pages render the form partial like so:
<%= render 'form' %>
This keeps the code dry so long as your form is the same for editing and creating.
All partial file names begin with an underscore, and if you want a partial to be available across your whole application put it in views/shared.
Some reading on partials.

Rails: form generation based on conditions

I've got a form to build a Document. That form needs adjusting depending on what type of Document a user has chosen. At this point I've got a deferring kind of method in new.html.erb that goes like this:
<%= render 'form_'+#template.label.downcase.parameterize.underscore %>
Which works fine but it's kinda difficult to manage though because when new types of documents are added I need to create actual HTML files and upload them.
Is there a better way to manage this kind of form generation? A view with hundreds of if statements in it feels cumbersome too.
You can push it to document_helper or decorator like :
module DocumentHelper
def form_render
return 'form_#{type}'
end
end

Allows user to edit pages that contain variables [duplicate]

This question already has an answer here:
How to render a string as an erb file?
(1 answer)
Closed 9 years ago.
I have some editable pages that are stored as text in my database. These pages will be called in my view like...
#app/views/static_pages/scheduling_text.html.erb
<%= Page.find_by_name("New Registration").content %>
Page.content is of type 'text' (not string). A portion of the text that contains variables would look like...
You have successfully registered for New Student Orientation on #{<%= #registration.orientation.class_date %>} at...
If course when I call this content in the view, I just get the text, not the model values. How can I make these pages access the model values? I also tried adding #{} around the text without success.
This seems to be a duplicate of Rails: storing erb templates in database
Given that, this should do the trick for you, or at least be close enough to get you started:
<%= sanitize ERB.new(Page.find_by_name("New Registration").content).run %>
Additionally, you can remove the sanitize if content is not user-supplied (this is primarily a security concern).
I've done something exactly like this using HAML processing:
= sanitize Haml::Engine.new(article.content).render
For reference, here's the appropriate ERB documentation: http://ruby-doc.org/stdlib-2.0.0/libdoc/erb/rdoc/ERB.html
OK, after much wailing and gnashing of teeth here is the the solution I cam up with. First I am using mustache. This is much safer than storing erb in the templates and prevents malicious injection of sql into your app. I simply added 'mustache' to my gemfile rather than mustache-rails as it seems to be more up to date. I then created a simple Page model with two attributes: :name and :content. I am using the page model to store the raw mustache code.
Here are the relevant files...
In my controller I call...
#app/controllers/registrations_controller.rb
def create
#registration = Registration.new(params[:registration])
respond_to do |format|
if #registration.save
if #registration.orientation != nil
format.html { render "scheduling_text.html.erb" }
Then my view looks like...
#app/views/registrations/scheduling_text.html.erb
<%= Mustache.render(Page.find_by_name("New Registration").content, {:registration => #registration }).html_safe %>
<%= link_to 'Back', orientations_path %>
...
Then in my page model I have something like...
You have successfully registered for New Student Orientation on {{ registration.orientation.class_date }} at {{ registration.orientation.class_time}}. Please arrive 10 minutes prior to your scheduled Orientation. Remember, you must attend this Orientation session before you may register for classes. ...
Using a page model with scaffolding like this works well because it gives you the new, update, and create actions that will allow users to edit content. Note, they can easily mess up your ruby variables, so thats the downside. Just let your users know to not munk with anything that is between {{}}.
Hope this helps someone else out.

What's the best way to do UJS in rails when you have a re-usable widget?

In my current project I have a couple instances where I have a re-usable form that exists inside a rails partial. This form submits to a specific controller via ajax (:remote => true). The controller does some stuff and then returns back the appropriate js.erb to modify the page via javascript.
This works fine for when I have a single view. But the problem seems to happen when this re-usable partial exists on multiple views. In view 1 I might want to issue a completely different set of javascript commands then in view 2.
As a concrete example, say I have a comments controller that has the normal CRUD operations.
I now have partial called _comments_box.erb. This _comments_box.erb contains the ability to submit a comment via a simple line:
- form_for comment, :url => post_comments_path(post), :remote => true do |f|
This submits to a comments_controller.rb create method which looks somethings like this:
def create
... do some stuff, like create a new comments model
respond_to do |format|
# will respond with create.js.erb
format.js
end
end
The create.js.erb in turn adds a comment to the view, perhaps doing a bunch of other updates to the DOM.
Say I render the _comments_box.erb within a view called post_summary.erb. Now I have another view, post_detail.erb that requires the same _comments_box.erb. However the post_detail.erb requires me to update completely different divs on the DOM in response to a new comment.
I need to create a different JS response for each instantiation. So I can either:
Create an alternate controller method, say create_2. Pass in some parameter to the _comments_box.erb from post_detail.erb to the _comments_box.erb partial so it knows which controller method to fire. This will allow me to have a separate file _create_2.js.erb that will allow me to manipulate the post_detail.erb view independently.
Forget about using js.erb altogether and just use plain old AJAX and get back JSON, and handle the javascript manipulation completely on the client-side.
It seems option 1 allows me to continue to use the UJS supported by Rails which is nice. But also means I probably will be adding a lot of duplicate code everywhere which is annoying. Is there a way for me to do this elegantly while continuing to use UJS?
That's exactly the purpose of Apotomo: http://apotomo.de/
Here is it's own description:
Apotomo is a true MVC widget framework
for Rails. Widgets are based on Cells
and provide reuseable view components.
Having bubbling events, they know when
and how to update themselves via AJAX!
Working with Apotomo widgets almost
feels like developing GUI components –
in a Rails environment.
Have a try, it's great.
I'd not recommend using UJS for frontend apps: server shouldn't take care of client side business. I agree it's useful and clean but it lacks performance and thus should be kept for backend stuff (RJS will move into a gem, see here: http://weblog.rubyonrails.org/2011/4/21/jquery-new-default).
That said, back to the solutions you expose:
1) I think you won't need an extra controller, you'd just have to pass additional params in order to know from where to query came from. A hidden_field could do the trick. With this info, render the good js.erb file
format.js { if condition
render "create.js.erb"
else
render "create_2.js.erb"
end
}
2) I'd go for it and return json but you'll face the same problem: knowing from where the request comes from.
A better solution (than using a hidden_field) might be to check the request.referer in your controller action. This way you leverage the fact that each context has a unique URL, and don't have to explicitly specify another unique value when rendering your widget partial.

Resources