rails exclude for multiple strings - html

I have the following code. This piece of code is working for me.But it looks ugly. is there any cleaner approach for achieving this?
<% if request.original_url.exclude?("/invest/") || request.original_url.exclude?("/study/") || request.original_url.exclude?("/work/") %>
some html tags here ...
<% end %>

Actually exclude? is defined in Rails is defined just as the opposite of include?, which would be very good if it's able to receive a regular expression, but it doesn't.
What you can do is to store in an array the substrings you want to check against the request.original_url, and use any? to check if any of those return true, which helps you to save a bit of characters, but would be good if that list increases.
You can try something like this:
['/invest/', '/study/', '/work/'].any? { |e| request.original_url.exclude?(e) }

First of all you should use helper and add following codes in it
exclude_ursl(request)
url_rules = ["/invest/", "/study/", "/work/"]
url_rules.each_with_object([]) do |url,urls|
urls << (request.original_url.exclude?(url))
end.include?true
end
Now use it in your view
<%if exclude_urls(request) %>
I don't have current such environment to test, so you can test it.

Related

How convert 'link_to' to Absolute in Rails

I've a problem in my program, I add in DB a link, for example, "www.google.com" and when I clic in the link I'm redirected to localhost:3000/www.google.com, this doesn't happen when I put "http://www.google.com" in DB.
My code
<td><%= link_to t.title, t.link_to_idea, :target => "_blank" %></td>
How do I make to convert this link always in absolute? (I think I this's solution)
Thanks!!
You could do something like:
<td><%= link_to t.title, t.link_to_idea.start_with?('http') ? t.link_to_idea : "http://#{t.link_to_idea}", :target => "_blank" %></td>
..but that assumes you want all links to save with http and not https.
You're probably better off checking for the protocol before you save the link in the DB.
For example, you could do what this answer suggests: Add http(s) to URL if it's not there?
before_validation :smart_add_url_protocol
protected
def smart_add_url_protocol
unless self.url[/\Ahttp:\/\//] || self.url[/\Ahttps:\/\//]
self.url = "http://#{self.url}"
end
end
That way you can just do what you already have.
I think your best bet is to update the links in your database to all conform to a standard format. You can also add a more basic validation to make sure all links match a valid format:
validates :link_to_idea, format: URI.regexp
You can also run a backfill on your database that checks old links to make sure they match this pattern and then update the ones that do not work. Are you using MySQL?
Either way, the best answer is not to try to make your app render any-old-thing that the user puts in, but to clean the data before it gets into the database.
If you can't control what goes into the database, then I would simply render, as text, anything that doesn't match that Regexp and let users put that into their browser on their own.
I'd suggest that you create a decorator using Draper. This will allow you to decouple presentation logic from your domain object.
Once you've set it up then you could write something similar to this:
# app/decorators/idea_decorator.rb
class IdeaDecorator < Draper::Decorator
delegate_all
def idea_url(protocol = 'https')
return link_to_idea if has_scheme?
"#{protocol}://#{link_to_idea}"
end
private
def has_scheme?
# .. some method here to determine if the URL has a protocol
end
end
And used in the view:
<%= link_to t.title, t.decorate.idea_url('https') %>

How to unit test html content generated by a Rails mailer?

I have come across a few tools that make it easier to test emails generated in a Rails app, but they are designed to be used in integration tests (i.e. capybara-email). However, I am writing a unit test that works directly with the mailer.
I currently have a test for my mailer that looks something like this:
RSpec.describe DigestMailer do
describe "#daily_digest" do
let(:mail) { DigestMailer.daily_digest(user.id) }
let(:user) { create(:user) }
it "sends from the correct email" do
expect(mail.from).to eql ["support#example.com"]
end
it "renders the subject" do
expect(mail.subject).to eql "Your Daily Digest"
end
it "renders the receiver email" do
expect(mail.to).to eql [user.email]
end
it "renders the number of new posts" do
expect(mail.body.raw_source).to match "5 New Posts"
end
end
end
However, I want to be able to test the html content a little easier than simply using regular expressions.
What I would really like to be able to do is something like this:
within ".posts-section" do
expect(html_body).to have_content "5 New Posts"
expect(html_body).to have_link "View More"
expect(find_link("View More").to link_to posts_url
end
I don't know if there is a way to use Capybara directly to achieve something like this. Maybe there are alternatives that can provide similar functionality?
According to this Thoughtbot article, you can convert a string to a Capybara::Node::Simple instance. This allows you to use capybara matchers against it.
I've created a helper method that uses this:
def email_html
Capybara.string(mail.html_part.body.to_s)
end
Which I can then use as follows:
expect(email_html).to have_content "5 New Posts"
Untested, but you should be able to include the Capybara Matchers into your mailer specs (like Capybara does for view specs by default) by adding
RSpec.configure do |config|
config.include Capybara::RSpecMatchers, :type => :mailer
end
and then in your test something like
expect(mail.html_part.body.to_s).to have_content('blah blah')
expect(mail.html_part.body.to_s).to have_link('View More', href: posts_url)
Note - this adds matchers, not finders, so you use the options to have_link rather than using find_link

How can I display the action of a database-linked form with sinatra?

I have been working on a project in Ruby's Sinatra with ActiveRecord and MySQL and have ran into an error: part of my site is adding a link to the database and I want to show all of the links on the next page but for some reason I can not seem to find out how to express this.
This is what I have so far:
get '/dashboard' do
#site = Site.find_by text: params[:text]
#sites= Site.all
#newsite = Site.new ({:text => :text})
#user = User.find_by_id session[:user_id]
erb :dashboard
end
This is what ERB page looks like:
<% #sites.each do |site| %>
<h4><%=site.text.to_s%></h4>
<% end %>
How would I solve this? Now my form works but it does not show anything after
Your ERB code references a #sites attribute which you don't set in the controller.
If you set #sites in your ruby code to be an array of the Site records you want to show, then you should see something.

Rails: Creating HTML in a Model

I have a Publication model with a has_many relationship to Contributors. In the model, I have a method that's meant to create an html-ready by line:
def authors
authors = []
Contributor.where(:publication_id => self.id).each do |author|
authors << "link_to "+author.name+", Contributor.find("+author.id.to_s+")"
end
authors.to_sentence
end
In my view, I have the following line:
by <%= #publication.authors %>
But instead of rendering links, it renders the raw code, such as:
by link_to B, Contributor.find(1)
I've tried patching this by adding .html_safe to the end of #publication.authors, but to no avail. Is there a better way to transfer these links from the model to the view?
You're pushing strings into your authors array. It looks like valid code, so running eval on it should work. (Actually author.name will probably evaluate as an undefined symbol, so scratch that.)
A better way would be to use a has_many :authors, :model => 'Contributor' relationship on your Publication model, and you can bring up your array of Contributor objects by simply calling
#publication.authors
You'd want to iterate over these in your view like so:
<% #publication.authors.each do |author| %>
<%= link_to author.name, author %>
<% end %>
Note also that if you're displaying multiple Publication objects in a view this way, you'll want to use Publication.includes(:authors) in your controller when you're retrieving them to avoid the "N+1" problem.
Now, three lines of code doesn't seem very expensive to repeat, but there are ways to DRY that without violating the MVC pattern and cluttering your model:
Place the code to print a publication's authors into a partial, and call the partial as needed.
Place the code into a helper, include the helper and call the method as needed.
Here's a snippet from the source for to_sentence (you can adapt it for your needs, I think):
case length
when 0
""
when 1
self[0].to_s.dup
when 2
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
else
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
end
The full source can be found here.
It looks like you are trying to use haml syntax in your line. Maybe instead of using link_to, use an html hyperlink tag itself?
That being said, why are you having a model return html?
Edit: bdares answered already with what I was trying to say

string with full stop in it not properly outputted in html

I have a Question model in my Ruby on Rails project with Postgresql database which has a string data type called question. (Original hey!) When I input some data with a full stop (.) in it, it doesn't print/output in my html/erb view file correctly, everything before the full stop is missing!
<div class="field">
<%= f.label question.question %><br />
....
It is storing in my database correctly as per the below output from the psql console
select question from questions where "id"=1;
question
----------------------------------
What is 2+3. What is the answer?
(1 row)
Does anyone know what is happening here (and the workaround)? I've tried things such as .html_safe and .to_s to no avail.
EDIT: also another thing that bothers me about the html output is that it gets rid of all my capitalized letters. Wtf?!
So the html output of the example about would be below...
what is the answer?
Not sure about the disappearing text part, but the label helper applies the humanize method to auto-generated label text (i.e. if no explicit label text is passed in). In the console it looks like this:
ruby-1.9.2-p290 :006 > helper.label_tag "All Caps String"
=> "<label for=\"All_Caps_String\">All caps string</label>"
As a workaround, try providing an explicit label value:
ruby-1.9.2-p290 :007 > helper.label_tag "All Caps String", "All Caps String"
=> "<label for=\"All_Caps_String\">All Caps String</label>
So try this:
<%= f.label question.question, question.question %>