Rails: join an array with a new line between each component - ruby-on-rails

I am trying to make an app in Rails 4.
I have this method:
def full_address
[self.first_line, middle_line, last_line, country_name].compact.join("\n")
end
When I try this, it prints a space between components.
I've read several posts on here that say that single quotation marks are the problem (I've also tried those). I also tried:
def full_address
[self.first_line, middle_line, last_line, country_name].compact.join("<br>")
end
When I try this, it prints 'br' between components.
How do I do this? I've seen responses in several other languages that talk about '+' signs being the solution. I've tried them, it doesnt work. I need help in rails please.
I'm trying to use this in my views show page as:
<%= #address.full_address %>

irb(main):004:0> puts ["a", "b", "c", "d"].join("\n")
a
b
c
d
You didn't show that part of the code but I suspect that the problem is that you're trying to put the result string in an HTML page. HTML ignores whitespace and that is why you don't get the newlines. You can try the solution you proposed with the <br> and try to add .html_safe

Related

what is the best way to get a portion of this url

I am creating like a link like so:
<%= link_to('', "#{issueable}/#{order.id}/issues" %>
which creates a link like this:
root/version2/parts/2418/issues
I want to be able to get the "parts" (/version2/parts/2418/issues) portion of that url when the user clicks the link to that controller method.
You can use split:
link = "root/version2/parts/2418/issues"
puts link.split('/')[2].strip
#outputs parts
link = "version2/parts/2418"
puts link.split('/')[1].strip
#outputs parts
Ruby fiddle
In other words, you've got a string "/version2/parts/2418/issues" and you want to extract the 'parts' position from it.
"/version2/parts/2418/issues".split('/')[-3]
You'll need to figure out yourself whether to get [2] from the split array or [-3]. As an added '/' in the beginning or in the end could mess it up.
You could use regex assuming you know that it starts with "version2" and also know the order_id when it gets to it.
"/version2/parts/2418/issues".match(/\/version2\/(\w+)\/2418/)
puts $1

Writing each line from Textarea in a single document

I want write mulitple lines from a textarea to a mongodb database:
First Line
Second Line
Third Line
etc.
Each line should be written in a single document.
So what I first figured out that I might use the gsub-function for separating the lines and after that I could write them with an each do - loop to the database.
And this point I got stuck.
Thanks in Advance for helping
Arthur's solution is correct if what you want is to put each line as sub-document of a single document.
If you really want multiple documents, then this may be the solution if it uses rails.
inputString=params["textareainput"]
lines=inputString.split("\n")
lines.each do |l|
Book.create(:content => l)
end
The code is placed in the controller (if you use MVC, probably in Rails framework)
So if you wanna have the lines split in your database, what would do, is something like this:
class Book
field :lines, type: Array
def text=(t)
doc = []
t.each_line { |l| dpc << l }
self.lines = doc
end
end

Rails way to offer modified attributes

The case is simple: I have markdown in my database, and want it parsed on output(*).
#post.body is mapped to the posts.body column in the database. Simple, default Activerecord ORM. That column stores the markdown text a user inserts.
Now, I see four ways to offer the markdown rendered version to my views:
First, in app/models/post.rb:
# ...
def body
markdown = RDiscount.new(body)
markdown.to_html
end
Allowing me to simply call #post.body and get an already rendered version. I do see lots of potential problems with that, e.g. on edit the textfield being pre-filled with the rendered HMTL instead of the markdown code.
Second option would be a new attribute in the form of a method
In app/models/post.rb:
# ...
def body_mardownified
markdown = RDiscount.new(body)
markdown.to_html
end
Seems cleanest to me.
Or, third in a helper in app/helpers/application_helper.rb
def markdownify(string)
markdown = RDiscount.new(string)
markdown.to_html
end
Which is used in the view, instead of <%= body %>, <%= mardownify(body) %>.
The fourth way, would be to parse this in the PostsController.
def index
#posts = Post.find(:all)
#posts.each do |p|
p.body = RDiscount.new(string).to_html
#rendered_posts << p
end
end
I am not too familiar with Rails 3 proper method and attribute architecture. How should I go with this? Is there a fifth option? Should I be aware of gotchas, pitfalls or performance issues with one or another of these options?
(*) In future, potentially updated with a database caching layer, or even special columns for rendered versions. But that is beyond the point, merely pointing out, so to avoid discussion on filter-on-output versus filter-on-input :).
The first option you've described won't work as-is. It will cause an infinite loop because when you call RDiscount.new(body) it will use the body method you've just defined to pass into RDiscount (which in turn will call itself again, and again, and so on). If you want to do it this way, you'd need to use RDiscount.new(read_attribute('body')) instead.
Apart from this fact, I think the first option would be confusing for someone new looking at your app as it would not be instantly clear when they see in your view #post.body that this is in fact a modified version of the body.
Personally, I'd go for the second or third options. If you're going to provide it from the model, having a method which describes what it's doing to the body will make it very obvious to anyone else what is going on. If the html version of body will only ever be used in views or mailers (which would be logical), I'd argue that it makes more sense to have the logic in a helper as it seems like the more logical place to have a method that outputs html.
Do not put it in the controller as in your fourth idea, it's really not the right place for it.
Yet another way would be extending the String class with a to_markdown method. This has the benefit of working on any string anywhere in your application
class String
def to_markdown
RDiscount.new(self)
end
end
#post.body.to_markdown
normal bold italic
If you were using HAML, for example in app/views/posts/show.html.haml
:markdown
= #post.body
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#markdown-filter
How about a reader for body that accepts a parse_with parameter?
def body(parse_with=nil)
b = read_attribute('body')
case parse_with
when :markdown then RDiscount.new(b)
when :escape then CGI.escape(b)
else b
end
end
This way, a regular call to body will function as it used to, and you can pass a parameter to specify what to render with:
#post.body
normal **bold** *italic*
#post.body(:markdown)
normal bold italic

Auto-removing all newlines from Haml output

I'm using Haml in a Rails 3 app, and its newlines drive me nuts! For example,
%span
foo
renders as
<span>
foo
</span>
But I'd much rather want
<span>foo</foo>
The reason (apart from being cleaner XML) is that extra newlines are a problem for my Selenium tests because they mess up the ability to do XPath queries like "//span[.='foo']". So I'd have to write '\nfoo\n' instead (ew!), or use //span[contains(text(), 'foo')], which matches too broadly.
I know I could use the alligator operators ("<" and ">") to strip whitespace, but since I don't ever have a case where I want the newlines to appear in the output, I'd just end up adding them mechanically at the end of each line. And that just seems very unDRY.
So now I see two solutions:
Force Haml to never emit newlines unless they come from a Ruby expression. I see some nuke_inner_whitespace / nuke_outer_whitespace variables spread around the Haml code that might do the job, but I'm not sure how to change them without resorting to gratuitous monkey-patching.
Hook into Rails to apply a gsub!("\n", "") to all rendered HTML. (For textarea's and pre's, I could still use ~ "foo\nbar" to make Haml emit foo
bar.) But where's the right place to hook into Rails? I'm a little lost in the code.
Any pointers or other suggestions appreciated!
Update: I've used Jason's monkey patch below for a while now and I'm beginning to think that it's not worth it. E.g. if I want to get <span>[del]</span> <span>foo</span>, it's difficult to not have the blank space in between nuked. Even the following will render as [del]foo on the page:
%span
= '[del] '
%span
foo
So I think I'm going back to adding alligator operators manually (see my self-answer down below). Live and learn.
Thanks again to Jason! :)
If you place a less-than sign at the end of the element name the whitespace around the content will be suppressed:
%span<
foo
See whitespace removal in the Haml reference for more details.
There doesn't appear to be any clean way to force these flags on for all tags but the following monkey patch works fine with Haml 3.0.24:
module Haml::Precompiler
def parse_tag_with_nuked_whitespace(line)
result = parse_tag_without_nuked_whitespace line
unless result.size == 9 && [false,true].include?(result[4]) && [false,true].include?(result[5])
raise "Unexpected parse_tag output: #{result.inspect}"
end
result[4] = true # nuke_outer_whitespace
result[5] = true # nuke_inner_whitespace
result
end
alias_method_chain :parse_tag, :nuked_whitespace
end
It probably wouldn't be hard to fork Haml and add an option to the Engine options to always nuke whitespace. The parse_tag method could check this option if enabled and set the inner and outer flags to true. I'll leave this as an exercise for the reader. :)
A few ways to do it:
%span foo
%span= "foo"
- foo = ["f", "o", "o"].join("")
%span= foo
%span #{"foo"}
- foo = ["f", "o", "o"].join("")
%span #{foo}
Similar to #yfeldblum's answer, I decided to simply split on newlines and join on spaces, in order to avoid newlines in html rendered into js. For example:
- content = capture_haml do
%div
%ul
%li Stuff
# ...
and then later,
:javascript
var stuff = "#{content.split("\n").join(" ")}";
// ...
Okay, I think I'll try to self-answer my question -- there's probably no clean/sensible way to remove all newlines, but perhaps I don't actually need that. For typical XPath test expressions to work nicely, it's enough if inline elements don't have newlines around them.
So I guess I'll just put an inner-whitespace-eater ("<") after any tag that contains inline elements (p, li, span, a, etc.). This seems to be working reasonably well so far. E.g.
%div
%ul
%li<
%span<
stuff...
And all the other (i.e. most) newlines can stay and won't do any harm.
Sorry everyone for the messy question!

Rails: Flatten array in parameter

I'm trying to flatten an array for my form.
def update
#tour = Tour.find(params[:id])
params[:tour][:hotel_ids][0] = params[:tour][:hotel_ids][0].split(',')
...
This results in:
"hotel_ids"=>[["1","2"]]
Naturally I want it to be
"hotel_ids"=>["1","2"]
My Form:
<%= text_field_tag 'tour[hotel_ids][]', nil %>
Hope anyone can help with this.
EDIT
I've gotten it to work, somehow. This might be a bad way to do it though:
I changed the text_field that get's the array from jquery to:
<%= text_field_tag 'tour[h_ids][]', nil %>
then in my controller I did:
params[:tour][:hotel_ids] = params[:tour][:h_ids][0].split(',')
And this works, I had to add h_ids to attr_accessor though. And it will probably be a big WTF for anyone reading the coder later... but is this acceptable?
This is ruby!
params[:tour][:hotel_ids][0].flatten!
should do the trick!
ps: the '!' is important here, as it causes the 'flatten' to be saved to the calling object.
pps: for those ruby-related questions I strongly suggest experimenting with the irb or script/console. You can take your object and ask for
object.inspect
object.methods
object.class
This is really useful when debugging and discovering what ruby can do for you.
Simply use <%= text_field_tag 'tour[hotel_ids]', nil %> here, and then split like you do in example.
What really happens in your example is that Rails get param(-s) tour[hotel_ids][] in request and it thinks: "ok, so params[:tour][:hotel_ids] is an array, so I'll just push every value with this name as next values to this array", and you get exactly this behavior, you have one element in params[:tour][:hotel_ids] array, which is your value ("1,2"). If you don't need (or don't want) to assign multiple values to same param then don't create array (don't add [] at the end of the name)
Edit:
You can also go easy way (if you only want answer to posted question, not solution to problem why you have now what you expect) and just change your line in controller to:
params[:tour][:hotel_ids] = params[:tour][:hotel_ids][0].split(',')
#split returns array and in your example you assigned this new array to first position of another array. That's why you had array-in-array.

Resources