rails saving recognized link from text to database with rinku - ruby-on-rails

I have a rails app with chat. In the chat for the messages I use rinku gem to recognize links which works well. On the top of this I would like to save the links as message.link without the rest of the text around it from the message.body.
So for example in the code below the user sent the message.body "hi there www.stackoverflow.com" and I would like to save only the "www.stackoverflow.com" as message.link. How can I do that?
view
<p><%= find_links(message.body) %></p>
controller
def find_links(message_body)
Rinku.auto_link(message_body, mode=:all, 'target="_blank"', skip_tags=nil).html_safe
end
it will appear in the DOM as:
<p>hey there http://stackoverflow.com/</p>
and will appear in the db as message.body:
"hey there http://stackoverflow.com/"
UPDATE:
messages controller
require "uri"
def create
.....
if message.save
link = URI.extract(message.body)
update_attribute(message.link = link)
end

You need regular expression to identify URLs from text. Try following regular expression:
/(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/
Working demo: http://rubular.com/r/bHQdFHZYFH
2.1.2 :001 > str = "hey hi hello www.google.com https://stackoverflow.com http://tech-brains.blogspot.in"
2.1.2 :002 > regexp = /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/
2.1.2 :003 > str.scan(regexp)
=> [["www.google.com"], ["https://stackoverflow.com"], ["http://tech-brains.blogspot.in"]]

You can use Ruby code:
2.0.0-p247 :001 > require "uri"
=> true
2.0.0-p247 :002 > URI.extract("hey there http://stackoverflow.com/")
=> ["http://stackoverflow.com/"]
Hope it helps!

Related

How do I write a function in rails console?

I am trying to write a function in the rails console, and in the example, this is how the function should look in terminal.
>> def string_message(str = '')
>> return "It's an empty string!" if str.empty?
>> return "The string is nonempty."
>> end
How do they create a new line while still making the console realize it is all of the lines create a function. Would it be accurate to write it as:
>> def string_message(str = '') \n\t return "It's an empty string!" if str.empty? \n\t blah blah \n\t
?
IRB, the ruby console in which rails console relies supports this out of the box.
Just type your function declaration, press the enter key, then input the body line by line, and finally type end.
You'll see text like this:
2.4.1 :001 > def say_hi(person)
2.4.1 :002?> puts "Hi #{person}"
2.4.1 :003?> end
=> :say_hi
2.4.1 :004 > say_hi("Nina")
Hi Nina
=> nil
2.4.1 :005 >
Notice how the ? indicates that IRB is waiting for more input before evaluating the expression.

How to integrate a simple bitcoin API into a Rails app

I am new to API's and backend development in general and have been trying for a few hours now to figure out how to do something simple like call the current bitcoin market price into my Rails app.
I tried referencing http://blockchain.info/ticker with the following code in my model
require 'rest-client'
require 'json'
base_url = "http://blockchain.info/ticker"
response = RestClient.get base_url
data = JSON.load response
cool = data[0]["CNY"]
#test = JSON.pretty_generate cool
and then put this in my view
<%= #test %>
I know this is way off but I'm at a loss and figured I would see if someone could provide a good resource or maybe get me going in the right direction. Many thanks
Dude, its all working good.
Replace data[0]["CNY"] with data["CNY"], thats all.
To get more handle, execute these lines 1 by 1 in irb,
Just like this,
1.9.3p385 :001 > require 'rest-client'
=> true
1.9.3p385 :002 > require 'json'
=> true
1.9.3p385 :004 > base_url = "http://blockchain.info/ticker"
=> "http://blockchain.info/ticker"
1.9.3p385 :005 > response = RestClient.get base_url
1.9.3p385 :006 > data = JSON.load response
1.9.3p385 :007 > cool = data["CNY"]
=> {"15m"=>5519.13613, "last"=>5519.13613, "buy"=>5578.16433, "sell"=>5853.54832, "24h"=>5616.47, "symbol"=>"¥"}
1.9.3p385 :008 > #test = JSON.pretty_generate cool
=> "{\n \"15m\": 5519.13613,\n \"last\": 5519.13613,\n \"buy\": 5578.16433,\n \"sell\": 5853.54832,\n \"24h\": 5616.47,\n \"symbol\": \"¥\"\n}"
1.9.3p385 :009 > p #test
"{\n \"15m\": 5519.13613,\n \"last\": 5519.13613,\n \"buy\": 5578.16433,\n \"sell\": 5853.54832,\n \"24h\": 5616.47,\n \"symbol\": \"¥\"\n}"
=> "{\n \"15m\": 5519.13613,\n \"last\": 5519.13613,\n \"buy\": 5578.16433,\n \"sell\": 5853.54832,\n \"24h\": 5616.47,\n \"symbol\": \"¥\"\n}"
I would recommend you use httparty which makes sending requests much simpler.
With regards to your example, you could do
require 'httparty'
require 'json'
base_url = "http://blockchain.info/ticker"
response = HTTParty.get(base_url)
data = JSON.parse(response.body)
data.each_pair do |ticker, stats|
pp "Ticker: #{ticker} - 15m: #{stats['15m']}"
end
Obviously I am pp (printing) out a string just to show the data. You would actually render the data in the view if you were to do a real implementation.

Rails / Ruby not following Rublar on regular expression

I have the following expression that I have tested in Rubular and that successfully matches against a snippet of HTML:
Official Website<\/h3>\s*<p><a href="([^"]*)"
However, when I run the expression in Ruby, using the following code, it returns no matches. I've reduced it down to "Official\s*Website" and it matches that, but nothing further.
Are there any additional options I need to set, or anything else that I need to do to configure Ruby/Rails to start tracking Rubular?
matches = sidebar.match(/Official\s*Website<\/h3>\s*<p><a href="([^"]*)"/)
if matches.nil?
puts "no matches"
else
puts "matches"
end
This is the relevant part of the snippet I'm matching against:
<h3>Official Website</h3><p>website.com</p>
your regular expression is correct. rubular should be working the same way your code does.
i tested it against ruby 1.8.7 and 1.9.3
irb(main):006:0> sidebar = ' <h3>Official Website</h3><p>website.com</p>'
=> " <h3>Official Website</h3><p>website.com</p>"
irb(main):007:0> sidebar.match(/Official\s*Website<\/h3>\s*<p><a href="([^"]*)"/)
=> #<MatchData "Official Website</h3><p><a href=\"http://website.com\"" 1:"http://website.com">
-
1.9.3p0 :005 > sidebar = ' <h3>Official Website</h3><p>website.com</p>'
=> " <h3>Official Website</h3><p>website.com</p>"
1.9.3p0 :006 > sidebar.match(/Official\s*Website<\/h3>\s*<p><a href="([^"]*)"/)
=> #<MatchData "Official Website</h3><p><a href=\"http://website.com\"" 1:"http://website.com">
if you want to quickly check why stuff is not working, you should try it in IRB or in your rails console. most of the times it's typo or bad encoding.

HTTP post request via Ruby

I'm very new to ruby and trying some basic stuff. When I send HTTP request to the server using:
curl -v -H "Content-Type: application/json" -X GET -d "{"myrequest":"myTest","reqid":"44","data":{"name":"test"}}" localhost:8099
My server sees JSON data as "{myrequest:myTest,reqid:44,data:{name:test}}"
But when I send the request using the following ruby code:
require 'net/http'
#host = 'localhost'
#port = '8099'
#path = "/posts"
#body = ActiveSupport::JSON.encode({
:bbrequest => "BBTest",
:reqid => "44",
:data =>
{
:name => "test"
}
})
request = Net::HTTP::Post.new(#path, initheader = {'Content-Type' =>'application/json'})
request.body = #body
response = Net::HTTP.new(#host, #port).start {|http| http.request(request) }
puts "Response #{response.code} #{response.message}: #{response.body}"
It sees it as "{\"bbrequest\":\"BBTest\",\"reqid\":\"44\",\"data\":{\"name\":\" test\"}}" and server is unable to parse it. Perhaps there are some extra options I need to set to send request from Ruby to exclude those extra characters?
Can you please help. Thanks in advance.
What you are doing on the shell produces invalid JSON. Your server should not accept it.
$echo "{"myrequest":"myTest","reqid":"44","data":{"name":"test"}}"
{myrequest:myTest,reqid:44,data:{name:test}}
This is JSON with unescaped keys and values, will NEVER work. http://jsonlint.com/
If your server accept this "sort of kind of JSON" but does not accept the second one in your example your server is broken.
My server sees JSON data as "{myrequest:myTest,reqid:44,data:{name:test}}"
Your server sees a string. When you will try to parse it into JSON it will produce an error or garbage.
It sees it as "{\"bbrequest\":\"BBTest\",\"reqid\":\"44\",\"data\":{\"name\":\" test\"}}"
No this is how it's printed via Ruby's Object#inspect. You are printing the return value of inspect somewhere and then trying to judge whether it's valid JSON - it is not, since this string you've pasted in is made to be pasted into the interactive ruby console (irb) or into a ruby script, and it contains builtin escapes. You need to see your JSON string raw, just print the string instead of inspecting it.
I think your server is either broken or not finished yet, your curl example is broken and your ruby script is correct and will work once the server is fixed (or finished). Simply because
irb(main):002:0> JSON.parse("{\"bbrequest\":\"BBTest\",\"reqid\":\"44\",\"data\":{\"name\":\" test\"}}")
# => {"bbrequest"=>"BBTest", "reqid"=>"44", "data"=>{"name"=>" test"}}
Your problem is something other than the existence of escape characters in the string. Those are not put in by the code you show, but by irb or .inspect. If you put in a simple puts #body in your code (or in a Rails context, logger.debug #body), you'll see this. Here's an irb session showing the difference:
ruby-1.9.2-p180 :002 > require 'active_support'
=> true
ruby-1.9.2-p180 :003 > json = ActiveSupport::JSON.encode({
ruby-1.9.2-p180 :004 > :bbrequest => "BBTest",
ruby-1.9.2-p180 :005 > :reqid => "44",
ruby-1.9.2-p180 :006 > :data =>
ruby-1.9.2-p180 :007 > {
ruby-1.9.2-p180 :008 > :name => "test"
ruby-1.9.2-p180 :009?> }
ruby-1.9.2-p180 :010?> })
=> "{\"bbrequest\":\"BBTest\",\"reqid\":\"44\",\"data\":{\"name\":\"test\"}}"
ruby-1.9.2-p180 :013 > puts json
{"bbrequest":"BBTest","reqid":"44","data":{"name":"test"}}
=> nil
In any case, the best way to do json encoding in Rails is not to call ActiveSupport::JSON.encode directly, but rather override as_json in your model or use the serializable_hash feature. This will make your code cleaner as well. See the top answers to this stackoverflow question for details.

Full url for an image-path in Rails 3

I have an Image, which contains carrierwave uploads:
Image.find(:first).image.url #=> "/uploads/image/4d90/display_foo.jpg"
In my view, I want to find the absolute url for this. Appending the root_url results in a double /.
root_url + image.url #=> http://localhost:3000//uploads/image/4d90/display_foo.jpg
I cannot use url_for (that I know of), because that either allows passing a path, or a list of options to identify the resource and the :only_path option. Since I do't have a resource that can be identified trough "controller"+"action" I cannot use the :only_path option.
url_for(image.url, :only_path => true) #=> wrong amount of parameters, 2 for 1
What would be the cleanest and best way to create a path into a full url in Rails3?
You can also set CarrierWave's asset_host config setting like this:
# config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.storage = :file
config.asset_host = ActionController::Base.asset_host
end
This ^ tells CarrierWave to use your app's config.action_controller.asset_host setting, which can be defined in one of your config/envrionments/[environment].rb files. See here for more info.
Or set it explicitly:
config.asset_host = 'http://example.com'
Restart your app, and you're good to go - no helper methods required.
* I'm using Rails 3.2 and CarrierWave 0.7.1
try path method
Image.find(:first).image.path
UPD
request.host + Image.find(:first).image.url
and you can wrap it as a helper to DRY it forever
request.protocol + request.host_with_port + Image.find(:first).image.url
Another simple method to use is URI.parse, in your case would be
require 'uri'
(URI.parse(root_url) + image.url).to_s
and some examples:
1.9.2p320 :001 > require 'uri'
=> true
1.9.2p320 :002 > a = "http://asdf.com/hello"
=> "http://asdf.com/hello"
1.9.2p320 :003 > b = "/world/hello"
=> "/world/hello"
1.9.2p320 :004 > c = "world"
=> "world"
1.9.2p320 :005 > d = "http://asdf.com/ccc/bbb"
=> "http://asdf.com/ccc/bbb"
1.9.2p320 :006 > e = "http://newurl.com"
=> "http://newurl.com"
1.9.2p320 :007 > (URI.parse(a)+b).to_s
=> "http://asdf.com/world/hello"
1.9.2p320 :008 > (URI.parse(a)+c).to_s
=> "http://asdf.com/world"
1.9.2p320 :009 > (URI.parse(a)+d).to_s
=> "http://asdf.com/ccc/bbb"
1.9.2p320 :010 > (URI.parse(a)+e).to_s
=> "http://newurl.com"
Just taking floor's answer and providing the helper:
# Use with the same arguments as image_tag. Returns the same, except including
# a full path in the src URL. Useful for templates that will be rendered into
# emails etc.
def absolute_image_tag(*args)
raw(image_tag(*args).sub /src="(.*?)"/, "src=\"#{request.protocol}#{request.host_with_port}" + '\1"')
end
There's quite a bunch of answers here. However, I didn't like any of them since all of them rely on me to remember to explicitly add the port, protocol etc. I find this to be the most elegant way of doing this:
full_url = URI( root_url )
full_url.path = Image.first.image.url
# Or maybe you want a link to some asset, like I did:
# full_url.path = image_path("whatevar.jpg")
full_url.to_s
And what is the best thing about it is that we can easily change just one thing and no matter what thing that might be you always do it the same way. Say if you wanted to drop the protocol and and use the The Protocol-relative URL, do this before the final conversion to string.
full_url.scheme = nil
Yay, now I have a way of converting my asset image urls to protocol relative urls that I can use on a code snippet that others might want to add on their site and they'll work regardless of the protocol they use on their site (providing that your site supports either protocol).
I used default_url_options, because request is not available in mailer and avoided duplicating hostname in config.action_controller.asset_host if haven't specified it before.
config.asset_host = ActionDispatch::Http::URL.url_for(ActionMailer::Base.default_url_options)
You can't refer to request object in an email, so how about:
def image_url(*args)
raw(image_tag(*args).sub /src="(.*?)"/, "src=\"//#{ActionMailer::Base.default_url_options[:protocol]}#{ActionMailer::Base.default_url_options[:host]}" + '\1"')
end
You can actually easily get this done by
root_url[0..-2] + image.url
I agree it doesn't look too good, but gets the job done.. :)
I found this trick to avoid double slash:
URI.join(root_url, image.url)

Resources