I have a model Post with a text attribute Body, and I want to be able to insert images into the text, using HTML tags, so an example Body value would look like this:
post.body = "this is text <img src='file.png'/> that was an image"
and then post.body.html_safe prints as text and an image. But this doesn't work on production, because the file name gets a unique hash during assets precompilation, so the only way to get the file's path is to use image_url. But when
post.body == "this is text <img src='#{image_url("file.png")}'"
the image's path is just literally "#{image_url("file.png")}" in plain text. I'm really confused about this because when I set the post.body in the view, it suddenly works, even though it's set to the same value. The only difference is where the value is set.
Here's a demonstration of what I mean:
Scenario 1
A post is created with a click and then edited with a form:
create button:
<%= link_to "new post", create_post_path %>
edit view:
<%= form_for(#post, url: update_post_path(#post)) do |f| %>
<%= f.text_field :title %>
<%= f.text_area :body %>
<%= f.submit "save" %>
<% end %>
controller:
class PostsController < ApplicationController
def create
#post = Post.create
redirect_to edit_post_path(#post)
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
#post.update_attributes(post_params)
#post.save
redirect_to root_path
end
private
def post_params
params.require(:post).permit(:title, :body)
end
end
The saved blog view:
<% Post.each do |post| %>
<%= post.body.html_safe %>
<% end %>
The picture is missing and this is the text in the source code:
<img src='#{image_url("file.png")}' />
Scenario 2
Same thing as in Scenario 1
The saved blog view:
" %>
Picture prints normally and in the source code the img src is the full path of the file.
What's the difference between these two scenarios??? I'm so confused. I feel like it has something to do with Rails security measures when the post_params are being used but I have no idea.
Scenario 1
When you do:
Post.each do |post|
post.body.html_safe
end
ERB will not inspect the post.body content to interpret Ruby code. Code into the #{...} syntax in a string is only interpreted when you declare a string in ruby code, not when it is present in a string coming from database from example.
Formulated another way, when ERB sees post.body, it only understands "output the content of the string", but it will not parse the string searching for ruby code inside #{}.
The scenario 2 works because it has nothing to do with scenario 1. Scenario 2 isn't about ERB outputting a string. In scenario 2, the line post.body = "<img src='#{image_url("file.png")}' />" is interpreted by the Ruby parser, which will search for #{} in the string being defined, and will execute the code inside those.
Wrong solution
The first solution that comes to mind would be to parse manually the post.body content so it interprets Ruby code inside #{}, but that would be a huge security vulnerability if some untrusted people edit the posts, as they could write any Ruby code in the post and get it executed.
In the same style, you could use ERB <%= ... %> instead of Ruby's #{ ... }. Example: ERB.new("My name is <%= name %>").result.
Better solution
Don't save Ruby code within the post.body. You could save only the image filename in the src, and before rendering the post, apply some preprocessing to replace the filename with the full path. You will need a Ruby library to parse the post html and find all the img tags. One such library is Nokogiri.
Related
I want to use a helper Method inside link_to tag as follows
<%= link_to "Home", root_path, class:"nav-link <%= activeLink('home') %>" %>
This is my helper method
def activeLink(action_name)
if controller.action_name == action_name
"active"
end
end
I am getting error saying;
ActionView::SyntaxErrorInTemplate in PagesController#about
I want that helper method to check the current action name and
set the 'active' CSS class if current action matches the input action name
Can you use nested <%= ... %> notation? No.
However, what you're looking for is a form of string interpolation. As mentioned in the comments Ruby variables can be converted to strings in a couple ways (full details outlined in the linked guide).
The primary method you'll see is by using #{} within a string ie "This is my string #{ruby_variable}".
Which means you could use the following:
my_string = "World!"
hello_world_string = "Hello #{my_string}"
hello_world_string
=> "Hello World!"
I am building a simple Rails app that has Users, Blogs, and Comments. The last thing I have to do is make a link on the blogs show page where comments show and have those links send the user to the comment/:id/edit page where they can edit their comment.
However, I'm not able to grab the comment ID correctly for some reason and even though I am getting thrown no errors I am not brought to the error form, just a blank web page that has my layout elements.
Here is my blogs controller's show action:
def show
#blog = Blog.find_by_id(params[:id])
#comment = Comment.new
# #current_comment = Comment.find(params[:id])
end
Here is my comments controller's edit action:
def edit
#comment = Comment.find_by_id(params[:id])
end
And here is where the link is in the Blogs show view:
<% #blog.comments.each do |c| %>
<div><%= c.content %></div>
<%= link_to 'Delete', "/comments/#{c.id}", method: :delete %>
<% end %>
The delete function works, but when I try to grab the comment id in the same way for the link to the comment view it does not work. Instead of seeing a number in the url like 1, 2, or whatever the comment id is, I see the #{c.id} syntax. Any thoughts?
<% #blog.comments.each do |c| %>
<div>
<%= link_to c.content, edit_comment_path(c) %>
</div>
<%= link_to 'Delete', c, method: :delete %>
<% end %>
In general you want to avoid hardcoding paths when possible as it makes your code more brittle and verbose.
As you have written it "/comments/#{c.id}/edit" is not even being evaluated since its not inside a ERB tag.
I suppose you mean this part:
<div><%= c.content %></div>
That's because the <div><a href="/comments/#{c.id}/edit"> part is outside a ERB block, therefore it is being interpreted as plain HTML, and that's what you see in the url. There's no variable expansion in plain HTML inside a ERB file.
Either use link_to:
<div><%= link_to c.content, "/comments/#{c.id}/edit" %></div>
or enclose the url part in ERB tags:
<div><%= c.content %></div>
This is the error I'm getting:
ActionView::MissingTemplate in Posts#index
Missing partial text_posts/_text_post with {:locale=>[:en], :formats=>[:html],...
Extracted source (around line #5):
3 </div>
4
5 <%= render #posts %>
Here's the code in the file app/views/posts/index.html.erb
<div class="page-header">
<h1>Home</h1>
</div>
<%= render #posts %>
I'm following along the 'Rails Crash Course' book and this is one of the steps to create a social network. I don't know the reason for the error.
I am assuming that in your posts_controller.rb file you have specified the following:
def index
#posts = Post.all
end
The reason why you are getting this error is because Rails is trying to display a partial for the variable #posts. What is implicit here, is that Rails is looking for a file named _post.html.erb in the folder app/views/posts/ and not finding anything. To fix this, you will have to manually create the file in that directory (Note that all partials begin with an underscore).
Now, if you are wondering what you should put in this partial, first you should know what <%= render #posts %> is doing. When it goes to the partial, it is iterating over all your posts and for each of them, it is going to do something. So your partial may look something like this:
<p>
<%= link_to post.title, post_path(post.id) %>
</p>
<p>
<%= link_to "Edit", edit_post_path %>
</p>
<p>
<%= link_to "Delete", post_path(post.id), method: :delete %>
</p>
Just know that what is implicit here, is that we already have a #posts.each do |post| given for us, so you only have to define whatever content you wish to display for each individual post.
Hope this helps!!
As you're using <%= render #posts %>, i'm am sure this will call the partial file with leading _ symbol on same directory. Please ensure you have already file with the name _posts.html.erb. IF you want to pass the value into partial, here i give you simple illustration :
Assume you have this in customer_controller :
def show
#customer= Customer.find(params[:id])
end
Then it instance will available on show.html.erb :
<p>Item: <%= #customer.name%></p>
These instance variables are available in layouts and partials as well, instead pass variables to partials as locals like:
// here is the same concept with your problem
// render "cust_name" find the filename leading with underscore
<%= render "cust_name", name: #customer.name%>
Above line of code will call the file with name _cust_name.html.erb that contains :
<h1><%= name %></h1>
Hope this helped.
So, I have this which displays emails to a user.
OLD CODE FOR REFERENCE:
<%= for email in #emails
# print the name
eml = email
eml
puts "<br>"
end
%>
FIXED, WORKING, STABLE CODE:
<% for email in #emails %>
<%= email %>
<br>
<% end %>
<%= puts #emails.inspect %>
As you can see, it was a problem of multiple line tag. Bazar that It would cause this problem, but not at all that it would cause A problem.
OLD:
And it is working great. One thing. So, EML is a ruby string with HIDDEN#HIDDEN.HIDDEN, but when it goes to display I get this on the rendered page: ["HIDDEN#HIDDEN.HIDDEN"], so why is it doing that? Inspected it, it isn't a hash. Just a string. What is happening here?
This syntax does not look quite right. If this is being rendered in a view using ERB, you probably want code that looks more like this:
<% #emails.each do |email| %>
<%= email %><br />
<% end %>
The way you have that written is very C#-looking. In Ruby it is more common to use the methods attached to the object. Enumerable objects like arrays could be iterated through using the each method and a special structure in Ruby called a block.
http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-each
I am trying to get my posts tagged with a certain tag to render. My code in the view is
Views/posts/sports.html.erb
<% my_posts = post.find_by_tag("sports") %>
<%= my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>
my controller for this looks like
def sports
#posts = Post.paginate(:page => params[:page], :per_page => 10)
#post = Post.find(params[:id])
#title = "Newest"
respond_to do |format|
format.html
format.json { render :json => #users }
end
end
I know I have to define the #post variable but I'm not sure what to define it as.
UPDATE
The problem I'm having is a "Couldn't find Post without an ID" error
Second UPDATE
def find_by_tag name
Tag.find_by_name(name).posts
end
Part of the problem, based on what is shown here, is that you are defining instance variables with Post object(s) in the controller, and then not using them for anything in the view. To retrieve a collection of all the posts tagged "sports," you'd do the following in the controller:
#sports_posts = Post.find_by_tag("sports")
and in the view:
<% #sports_posts.each do |post|
etc...
To add pagination, you can just chain that method to the original:
#sports_posts = Post.find_by_tag("sports").paginate(:page => params[:page],
:per_page => 10)
This is different from your snippet, where you define a #posts variable that returns a collection of 10 Post objects, and #post which simply finds a post object based on the id passed by the submitting form params. My guess is that this controller action is not getting created by a form submission, so no params are passed, and therefore params[:id] is nil, hence the error messages you see. In any event, unless you need either of those items in your view (and there's nothing here to suggest they're being used for anything), there's no reason to create them.
What you do need is a collection of posts tagged "sports", which is what the call above accomplishes. It looks like you are trying to do that with post.find_by_tag("sports") in the view. The problem is that you are calling the find_by_tag method on post, which doesn't exist. Post exists - that's the Post class, and probably what you mean to be calling. Just changing post to Post would probably get you where you want, but content retrieval and presentation are better separated if you create your objects in the controller and then use the view to simply render their attribute data (per the example above).
You don't say what's going wrong, you only say what you're trying to do.
A few things to help debug whatever it is you are seeing:
<%= debug(params) if Rails.env.development? %>
In your main layout, this will dump the params hash and may lend a clue.
Also,
rake routes
Make sure you are looking for the right parameter key(s).
In the snippet you provided, you have an equals in front of the my_posts.each ... line, I am not an ERB expert, but I would think you would not want that, instead this:
<% my_posts = post.find_by_tag("sports") %>
<% my_posts.each do |post| %>
<%= post.title %><br />
<%= post.body %><br />
<% end %>