I've a text attribute for a model named :settore_scientifico_progetto and three string attributes, :macrocat, :cat, :microcat:
class Modulo1 < ActiveRecord::Base
before_create :set_settore_scientifico_progetto
before_update :update_settore_scientifico_progetto
private
def set_settore_scientifico_progetto
self.settore_scientifico_progetto = "#{macrocat}\n#{cat}\n#{microcat}"
end
def update_settore_scientifico_progetto
self.settore_scientifico_progetto = "#{macrocat}\n#{cat}\n#{microcat}"
end
I'd like to put a new line where I typed \n but the code I posted gives me the output
macrocat cat microcat.
I would like it as follows:
macrocat
cat
microcat
The output is shown in show.html.erb:
<div class="form-field">
<h3>Settore scientifico:</h3>
<p><%= #modulo1.settore_scientifico_progetto %></p>
</div>
Rails has a helper specifically for this purpose called simple_format.
<%= simple_format #modulo1.settore_scientifico_progetto %>
This will output the following HTML:
<p>macrocat<br/>
cat<br/>
microcat
</p>
Which is rendered by your browser like this:
macrocat
cat
microcat
That seems to be exactly what you're looking for, and it takes care of sanitizing your HTML for you. (Options for customizing the output, e.g. changing the wrapping tag or HTML attributes, are listed in the docs.)
P.S. Using the gsub...html_safe method advocated above is very risky. If your app accepts user input for any of the attributes you're printing, calling html_safe on those values means they won't be sanitized by ActionView and a malicious user could inject code into the view that makes your app vulnerable to cross-site scripting (XSS) attacks. Here's a good primer on the ins and outs of html_safe in Rails.
Related
I have an object that has an attribute using a markdown language for the past few years and recently the attribute is now switched to using html. How do I render all the past campaign descriptions with the markup language and how do I render all the new campaign descriptions with .html_safe
Html_safe
<h6 class="text-muted" itemprop="description">
<%= #campaign.product_description.html_safe %>
</h6>
Markdown
<h6 class="text-muted" itemprop="description">
<%= Campaign::Format #campaign.product_description, {render_html: true} %>
</h6>
How can I render both? That way For all the old campaigns it renders the markup and for the new campaigns it renders the html. When I include html_safe and the markdown on the same line it only does the markup and not the html from a WYSIWYG editor.
Several options:
Add a flag to your campaigns. Something like uses_html_description. Set its values correspondingly. And switch on that in the view.
Do a data migration and replace all descriptions in old format with the new html format.
Between these two, I'd go with the latter.
My first thought is that I would backfill your DB converting all the old records to the new format.
Otherwise, make a view helper method in app/helpers/application_helper.rb something like:
def description_text campaign
if campaign.created_at > Time.new(2019,3,1).in_time_zone
campaign.product_description.html_safe
else
Campaign::Format campaign.product_description, {render_html: true}
end
end
Note that you can probably also actually detect the HTML in the string if you'd prefer that to the time-based thing, like:
def description_text text
if text.starts_with? "<html" # or whatever
# ...
When I did this in ERB, it works as expected, giving me an a tag that wraps around an image and some text
<%= link_to(...) do %>
<img src="..." />
text
<% end %>
But when I tried to put this in a method, the a tag only wraps the last argument, which in this case, is the text.
def build_link
link_to(...) do
image_tag(...)
text
end
end
Looking at the docs, they only gave an example of using link_to in ERB, so is it smart to assume that using it in a method doesn't work as well and can't accept two parameters?
Following up to my comment:
The reason is behavior happens is because of how Ruby handles blocks, and how Rails handles the output for ActionController.
The trick here is to use handy-dandy concat.
def build_link
link_to("#") do
concat image_tag("http://placehold.it/300x300")
concat "hello world"
end
end
Pretend the block you pass to link_to is just another method, and it gets returned some object/value. In this case, your text object gets returned.
But because you want to output both image_tag and text, you need to pass that together to the output.
I'm trying to create a situation where one user makes message templates and another one can plug in values. I'm using the best_in_place gem, which will allow a user to edit the message on the show page.
The problem is this. When I call the message, with the required erb to make the gem work, it treats all of this as a regular string, not as ruby.
This is unclear, I'm sorry.
Here's the code.
#announcement.content = "The <%= best_in_place #announcement, :train %> is arriving in five minutes."
/show.html.erb
<%= #announcement.content %>
I want it to put "The click to set train is arriving in five minutes." and if the user clicks where it says "click to set train," a text field will open for them to edit (this is something the best-in-place gem does).
Instead, it puts "The <%= best_in_place #announcement, :train %> is arriving in five minutes."
I understand why it is doing this, but I don't know how to make it instead interpret the ruby I'm trying to pass in.
Ideas?
Use regular old string interpolation:
#announcement.content = "The #{best_in_place #announcement, :train} is arriving in five minutes."
You can use ERB to render any ERB template string. In this case something like:
<%= ERB.new(#announcement.content).result %>
Although you likely won't have access to all your Rails helpers, etc.
The Rails way to do this:
#announcement.content_type = :arriving
Later:
<%= render(partial: #announcement.content_type)
In _arriving.erb:
The <%= best_in_place #announcement, :train %> is arriving in five minutes.
TL;DR: ERB is not Ruby, and Rails uses both at different times.
You want simple Ruby string interpolation here:
#announcement.content = "The #{best_in_place #announcement, :train} is arriving in five minutes."
This is unclear, I'm sorry.
Not to worry, the Rails framework throws so many different new concepts at you it can be frustrating for newcomers.
Start from this: the Ruby framework builds the answer to the user's browser from a collection of resources Each file is evaluated by an interpreter for its own language. The trick is: look at the extension.
Files ending in .coffee will be compiled into javascript, files ending in .scss will become CSS, and in the same way files ending in .erb will yield HTML.
ERB is a language composed of mostly HTML already, plus a tag that allows you to interpolate Ruby. ERB stands for Embedded Ruby.
What about files ending in .rb, like the file in which you (surely) are evaluating #announcement.content = "The <%= best_in_place[...]" (a controller, I guess)?
Well, that's just pure Ruby :) that's why the ERB interpolation syntax <%= ... > is not recognized.
What you want to do in the controller, is (as you're trying to do) preparing the data for the view. The ruby in the <%= ... > tag in ERB will have access to the controller's instance variables, i.e. the variables with an # in front defined in the controller. But to define those, inside the controller, you should rely on Ruby alone.
Take-home message:
Be aware of which language you are writing in at each moment. For example:
# show.html.erb
<p>Here is ERB, which will be interpreted straight into HTML</p>
<% "Inside the '<% ...' tag is Ruby, but results won't show up in the HTML because there's no '<%='."%>
<% which_language = "Ruby" # Even variable assignments, and comments, do work %>
<%= "Inside the '<%=' tag, you're writing and interpolating #{which_language} :)" %>
I think the fact that I wasn't clear made it hard to answer this question.
What I'm doing is transforming user-inputted text (using a method in the model, called by the controller) to replace certain keywords with erb tags that call the best_in_place plugin. In my view, when presenting this content to another user, I wanted to call this content, which is saved as an attribute in the database, in such a way that it would render correctly for the other user to have the best_in_place functionality active.
Here's what I ended up doing. It is working, but if you have better ideas, please let me know.
In the announcements#create view, the user creates an announcement with certain pre-defined blocks of bracketed text as well as free-input text. For example, they might write "[train] is leaving from [platform] in [time] minutes."
When they hit save, the controller's create action calls the construct_message method from the model. It looks like this:
def construct_message(msg)
msg.gsub! '[train]', '<%= best_in_place #announcement, :train_id, :as => :select, collection: Train::list_trains, place_holder: "Click here to set train." %>' #note: list_trains and list_platforms are methods on the model, not really important...
msg.gsub! '[platform]', '<%= best_in_place #announcement, :platform_id, :as => select, collection: Platform::list_platforms, placeholder: "Click here to set platform." %>'
msg.gsub! '[time]', '<%= best_in_place #announcement, :number_of_minutes, placeholder: "Click here to set." %>'
end
Then, when I want to show that attribute in my view, I'm using render :inline, like this.
on announcements/:id
<p id="notice"><%= notice %></p>
<p>
<strong>Content:</strong>
<% announcement = #announcement %>
<%= render :inline => announcement.content, locals: { :announcement => announcement } %>
</p>
This allows the erb call that I wrote into the attribute to be functional.
Also note that I'm choosing to use a local rather than instance variable here; this is because in announcements#index, I also render this text and the table there uses local variables.
I am very new to Rails, and been asking lots of questions recently, I'm getting increasingly frustrated with figuring out how to work things in rails (i.e logging to console, routes, etc..), now I'm trying to figure out how to communicate between an HTML form (and please raw HTML, not form helpers or any of that voodoo magic, I really am trying very hard to like rails, so one thing at a time), if you want to add helpers, please explain what they are doing, where they go, how to use, etc...
I've tried all the examples on the first/second google page (gruesome I know! second google page?!)
What I am looking for is an example, and an explanation.
Also, how does it fit in with routes? (i.e what would be the proper way of setting up a controller/view, and routing them without the controller in the URL)
Please keep in mind, I am not using any models, just controllers, and views.
Your thoughts are much appreciated.
Oh no! Sorry that Rails is giving you grief, especially about form helpers! It's a shame because Rails' form helpers are pretty great, and IMHO are a super useful part of Rails in reducing code duplication, and allowing you to not worry about the specific field names that you are submitting to a server. (They're hard to get accustomed to, but worth it.)
Let me give you a summary of Rails form helpers. For starters, let's take this a simple example
<form action='/users' method='POST'>
<input type='text' name='username' />
<input type='password' name='password' />
<input type='submit' name='Create user' />
</form>
Ah, the most basic user signup form imaginable. This will POST to /users, which is REST-convention for "create a user".
The Rails Routing guide tells you that if you have a controller UsersController (in app/controllers/users_controller.rb -- the filename must be exactly this) and a route resources :users, then this will call the code in the create method of UsersController, and you will have access to the form POST data via the params hash, i.e. params[:username], params[:password], etc.
It is in that controller action where you would create an instance of your User model and save it to the database. (If you aren't using models, you're missing out on most of the magic of Rails's forms.)
Okay. So far so good, right?
Let's spice things up a bit by using Rails's form helpers.
A quick rewrite of the form using basic Rails form helpers would look something like this.
<%= form_tag '/users', method: 'POST' do %>
<%= text_field_tag 'username' %>
<%= password_tag 'password' %>
<%= submit_tag 'Create User' %>
<% end %>
So far, no Rails magic - it's a straight translation into HTML.
Let's add some Rails marrying.
Again, assuming you have a User model with a username column and a password attribute (attr_accessor :password), and your UsersController's #new method looks like this:
def new
#user = User.new
end
Then, in this form (which lives in app/views/users/new.html.erb), you can use that unpersisted User object to make the form more intelligent:
<%= form_for #user do |f| %>
<%= f.text_field :username %>
<%= f.password :password %>
<%= f.submit 'Create User' %>
<% end %>
Note the do |f| part of the form_for line. The f is a form object, which remembers the object it describes. So, you can call f.text_field :username, and the field will magically have the existing value of #user.username populated as the value of the <input>.
Then, if you have a UsersController#create method that looks something like this:
def create
# Instantiate a new user with the inputted parameters from the form
#user = User.new(params[:user])
if #user.save
# user is saved successfully! redirect somewhere....
else
# user couldn't be saved successfully, because of some rule that you
# define on the User model - like making sure that usernames are
# unique, or something like that.
#
# so, we can use the attributes on #user to prepopulate the new user form
render :new
end
end
Anyway, I hope that gives you a good overview of why Rails form helpers can be useful, and how to use them with your models. Let me know if you have any questions!
I have a question in using luquid. My question is like this,
I have a model called 'Page' (with is an ActiveRecord::Base
inherited) , and it has a column called 'content' which will store
the html page content.
I have a code to display it as follows
<%#template = Liquid::Template.parse(page_content) %>
<%= #template.render('page_content' => yield) %>
where 'page_content' has implemented in application helper as follows
def current_site_layout
Page.find(1). content
end
but my problem is if I have content as follows
<h1>This is a test</h1>
It will display in the page as
<h1>This is a test</h1> (with <h1></ h1> tags)
where as I want it to print like This is a test (formatting
applied as h1)
what am I missing here , and I think I will have to use liquid_methods
or something like that. But since I'm new to liquid I'm not sure which
method to use.. can someone help me
I'm on rails3 and using gem 'liquid 2.2.2', from 'github.com/GnomesLab/
liquid.git'
thanks in advance
cheers
sameera
In rails 3, strings are escaped by default. To display unescaped strings, you need to call raw method explicitly.
<%#template = Liquid::Template.parse(page_content) %>
<%= raw #template.render('page_content' => yield) %>