Message Module + handling links for private messages + rails - ruby-on-rails

i'm creating an application where i need to send a private message to a user and ask him/her for a confirmation on whether they would like to join or not. I have created a private message module and whenever i want to send a message, i do something like :
def sendMessage(attributes)
subject = 'whatever'
body = 'whatever'
current_user.sendMessage(current_user, subject, body)
end
Then, i get this message and print it out to the needed places, using <%=h %> for escaping stuff. My problem now is, what happens if i want to include 's or even more importantly <%= link_to %> inside that ?
How can i insert such things to be printed out and also be careful about escaping the user provided attributes ? I was thinking of creating sort of like a partial to do this for me, but i would certainly like to hear what you think about it.
Thank you :)

First off, you probably should name your method send_message since that tends to be the convention in Ruby and Rails.
For the question, why not do this:
<p><%=h user_submitted_info %> and check out this <%= link_to "Awesome Link", "/" %></p>
This will escape the user submitted content but leave the link_to alone. Why does the user submitted content and the link need to be in the same ERB tags?

Related

How to interpolate ruby inside of an interpolated bit of ruby in ERB

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.

setting a dynamic link_to rails

I'm pretty new to rails and I'd like to set my links for a certain page dynamically. I have a table called "Unfinished" and it has a column called "link" (corrected from "links") I'd like to be able to call the "link" record in the view to set my link_to link path.
I am trying to do this...
<%= link_to #unfinished.link(:p => #post.id) do %> FINISH <% end %>
...but that's not working.
my controller says:
def show
#post = Post.find(params[:id])
#unfinished = Unfinished.where('progress = ?', #post.progress).last
end
and the controller logic works fine...until I try to put the #unfinished.link into link_to
Edit:
Error Message:
wrong number of arguments (1 for 0)
Model
class Unfinished < ActiveRecord::Base
end
The type of links are :
step1_path
step2_path
step3_path
I am making a multipage form that you can save partway through. Based on a value in the #post.progress column (like 1, 2, 3) the correct path to complete the post will be provided (step1_path, step2_path etc...)
try this.
<%= link_to eval(#unfinished.link.to_s) do %> FINISH <% end %>
since the link you want is actually a named route, so you will need to eval it.
but with this you wouldn't be able to be able to pass in the post id, which you will need.
If the route is the same for all records (save for what part you are on based on the progress attribute) do you even need to store it in the database? You could just make the link method return the path (that you would still need to eval).
something like
def link (post)
"step#{self.progress}_path(post.id)"
end
and then eval the link on the way back. but Not sure if that will work, just thinking out loud...
There are gems that do multi-stage forms perhaps looking into them might help?

Using link_to in Rails 3 on the end of a string

There is probably a really simple answer to this but, as I'm a Rails newbie, I'm having great difficulty identifying the appropriate syntax.
Basically, I want to display a string with a link on the end, in which "Jimmy" here represents both the individual record and the link to that record:
"This video was posted by Jimmy"
I'd like to create a local variable to store the string, so my initial thought was to create the variable as follows:
my_string = "This video was posted by " + (link_to user.name, user)
However, this doesn't appear to work. Instead, it simply displays the generated HTML in the browser, i.e.:
This video was posted by Jimmy
This isn't what I want - I obviously want it to display:
This video was posted by Jimmy
in which Jimmy is the link.
Any ideas? I've tried adding .html_safe to the end of the string, but that doesn't work.
Thanks!
A much easier way to do this would be:
<td>Video created by <%= link_to user.name, user %></td>
No need to use string concatenation or use <%= "Video created by" %>, there's no need to run that through the Ruby parser, just use the plain text version :)
Check out raw
<%= raw my_string %>
Though, assuming this is in your view, I don't know why you'd be storing this to some my_string variable.
<span>This video was posted by <%= link_to user.name, user %></span>
Thanks for your help! I managed to fix the issue without needing to declare a variable (I was trying to be too clever).
The final (elided) code, in case anyone is interested, is as follows (in a table cell):
<td><%= "Video created by " %><%= link_to user.name, user %></td>
As always, it turns out the code is much easier to apply once you know how :-)
Thanks again!

Rails 3 / Controller / Flash hash

I want to be able to pass multiple messages to the flash hash, inside of my controller, and have them display nicely together, e.g., in a bulleted list. The way I've devised to do this is to create a helper function in my Application Controller, which formats an array into a bulleted list, which I then pass to, in my case, flash[:success]. This is clearly not the Rails Way because, i.a., my bulleted list gets encoded. That is, instead of getting:
Message 1
Message 2
I get:
<ul><li>Message 1</li><li>Message 2</li></ul>
I'm sure I could figure out a way to raw() the output, but isn't there a simple way to get something like this working? Perhaps there's an option to pass to flash[]? Something else?
I used render_to_string and a partial instead of a helper to achieve something similar.
# app/controller/dogs_controller.rb
def create
#dog = Dog.new(params[:dog])
#messages=[]
if #dog.save
#messages << "one"
#messages << "two"
flash[:notice] = render_to_string( :partial => "bulleted_flash")
redirect_to(dogs_path)
else
render :action => 'new
end
end
Then I format the array of flash messages in an HTML list
# app/views/dogs/_bulleted_flash.html.erb
<ol>
<% #messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ol>
Which produces the following HTML
# http://0.0.0.0:3000/dogs
<body>
<div id="flash_notice">
<ul>
<li>one</li>
<li>two</li>
</ul>
</div>
...
</body>
If you need to continue using a helper then I think you need to append the html_safe method to your string to prevent it from being encoded (which rails 3 does by default). Here is a question showing how to use html_safe in a similar fashion
If you are using Rails3, try the raw method.
raw(my_html_string)
And it won't escape the html. Oh, sorry, I just read your last sentence. Check out this information, "Rails 3 flash message problems", it looks like it may be what you are looking for:
http://www.ruby-forum.com/topic/215108
Usually I would ask for more information about your views and layouts in this situation, because scaffolding doesn't display flash[:success] by default.
The way I solve this is to totally redo my flash messages usually, by making the flash[:whatever] an array every time, and in my layout handling that array instead of just the notice. Remember that flash is just a Hash, you're just setting values.
However if you just want to do this with the setup you have now (helper putting the HTML inside the flash[:success]), you can change the way that the flash messages are displayed in your layout file. By default they are just use <%= flash[:success] %>, which automatically escapes HTML. To make it not do that for the flash messages, change it to <%=raw flash[:success] %>

Custom links in Rails

Rails has a few built in helper methods for dealing with links (url_for, link_to, auto_link), but none do exactly what I need:
I want the user to be able to specify a URL, and for me to be able to alter the text it appears as. auto_link almost does what I want, except you can't change the link text, and it doesn't recognize links that are typed in like: stackoverflow.com. You have to enter www.stackoverflow.com
I want the user to be able to enter something like "stackoverflow.com", and for me to be able to generate html like this:
Username
Is there a plugin out there that adds additional link helper methods?
You can pass a block to auto_link, and the result of that will be the link text. For example:
<% str = "something like http://stackoverflow.com would be the input" %>
<%= auto_link(str) do |url|
"Username"
end
%>
generates this HTML:
something like Username would be the input
And if you wanted the link text to be different depending on what the URL was, you could do something like:
<% str = "something like http://stackoverflow.com, and another http://stackexchange.com url" %>
<%= auto_link(str) do |url|
if url.match(/overflow/)
"Username"
else
"Something"
end
end %>
which generates:
something like Username, and another Something url
This plus the tips in the comments about adjusting the URL regex seem like they would do what you want.

Resources