How to make a mailer not repeat itself - ruby-on-rails-3

So I have managed to create some interesting behavoir that I have no idea how to debug. I have a mailer backed by a model and table. When the user creates a message a method generates an array of contacts to send the email to. We'll pick up there since that has been tested in console.
The model simply itterates through an array of recipients...
class ContactMessage < ActiveRecord::Base
...
def send_message(user)
self.recipients.each do |rec|
unless rec.include?("#")
contact = Contact.find(rec)
to = "\"#{contact.first_name} #{contact.last_name}\" <#{contact.email}>"
else
to = rec
contact = user.contact.new('email' => rec)
end
ContactMail.direct_mail(user, self, to, contact).deliver
end
end
end
It should then make n number of new calls to the ContactMail.direct_mail method.
class ContactMail < ActionMailer::Base
helper :mail
def direct_mail(user, contact_message, to, contact)
#user = user
#contact = contact
#contact_message = contact_message
#theme = #contact_message.theme
mail(:to => to, :subject => contact_message.subject, :from => "no-reply" << #user.website.domain, :reply_to => #user.email)
end
...
end
the mail() method renders the view using the #instance variables provided.
<%= #user.website.title %>
<%= #user.website.motto %>
============================================================
<%= #contact_message.message.html_safe.gsub(/<\/?[^><]*>/i, "") %>
============================================================
This message is from <%= #user.first_name << " " << #user.last_name << " of " << #user.business%>
Please reply to <%= #user.email %>
<%= #user.telephone %>
<%= #user.address_l1%>
<%= #user.address_l2 unless #user.address_l2.blank?%>
<%= #user.city << ", " << #user.state << " " << #user.zip %>
<%= #user.website.domain %>
All is well and good, I am using MailCatcher to recieve all of the emails and terminal says they were sent.
However, each mail sent after the first the << #instance just keeps piling up onto eachother! It produceses something like
Healthy Living
Where massage makes health.
============================================================
asdfasdfasdfasd
============================================================
This message is from Adam Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC Fluke of Healthy Living LLC
Please reply to fluke.a#gmail.com
504-638-2222
1822 Moss St
Apt E
New Orleans, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119, AL 70119
healthyliving.org
(this would be the fifth message sent, it gets progressively worse with each email sent.)
This is what I don't understand, based on my understanding of Mail and method calls, each message sent should be their own unique object and should not be interacting with eachother at all. Yet, the clearly are. This happens with += and <<, in text and html. WTF?
Any thoughts or help appreciated.

You are actually modifying your instance variables by using <<. If you use + I think it should work.

Related

Jquery UI auto complete rails including association

I am trying to implement an auto complete feature similar to facebook city selector where one enters the city name and the autocomplete appears in the form "city, state, country".
I have dbs of cities states and countries
I followed the railscast auto complete video.
My code is as follows
Cities controller
def index
#cities = City.order(:name).where("lower(name) like ?", "%#{params[:term].downcase}%")
render json: #cities.map(&:name)
end
User.js.coffee
jQuery ->
$('#user_city_name').autocomplete
source: $('#user_city_name').data('autocomplete-source')
users/new/html.erb
<div class="field">
<%= f.label :city_name %><br />
<%= f.text_field :city_name, data: {autocomplete_source: cities_path} %>
</div>
the city is all that needs to be auto selected but I would like when the user is selecting that they see the auto select option as city, state, country because there are a lot of cities with the same name in different states. can anyone point me in the right direction plz and thank you
I figured out how to do it. Changed the cities controller index to
def index
if params[:term]
#cities = City.order(:name).where("lower(name) like ?", "%#{params[:term].downcase}%").includes(:state)
cities_list = #cities.map {|city| Hash[id: city.id, label: "#{city.name}, #{city.state.name}, #{city.state.country.name}", value: city.name]}
render json: cities_list
else
#cities = City.all
end
end

Rails 3 deserialize array

This is my first time serializing. I serialized an array of checkboxes w/ jQuery on the client side, put it into a hidden element, and submitted the form. Now on the server side I want to deserialize into an array I can use. Here is my string on the client side.
someArray%5B%5D=value0&someArray%5B%5D=value1
In Rails 3, I would like to get an array that looks like:
["value0", "value1"]
Thanks!
Rack will automatically parse these values if you submit them as typical post parameters to your request. For example:
curl http://yoursite.com -d "array[]=somevalue&array[]=othervalue"
This will then be available as params[:array] within your application, containing two elements with the values specified.
For serialization i came up with something and i've got working in production for a while.
Lets say i've got a Car model with 3 different type of gadgets. (Lets assume i dont want 3 fields in DB):
in your database must be a field named gadgets as TEXT (ths is very important)
in Car.rb
serialize :gadgets
attr_accessible :alarm, :ac, :tires
ALARM = 0;
AC = 1;
TIRES = 2;
# this is the getter for alarm
def has_alarm
if self.gadgets.nil?
return 0
else
if self.gadgets[ALARM].nil?
return 0
else
return self.gadgets[ALARM]
end
end
# this is the setter for alarm
def has_alarm=(value)
self.gadgets = Array.new if self.gadgets.nil?
self.gadgets[ALARM] = value
end
# getter
def has_ac
if self.gadgets.nil?
return 0
else
if self.gadgets[AC].nil?
return 0
else
return self.gadgets[AC]
end
end
# setter
def has_ac=(value)
self.gadgets = Array.new if self.gadgets.nil?
self.gadgets[AC] = value
end
...
in your _form.rb
<%= f.check_box :has_alarm %> I want alarm in my car
<%= f.check_box :has_ac %> I want AC in my car
<%= f.check_box :has_tires %> I want deluxe tires in my car
I hope you dont have to search by these fields later...

How to make parts of Profile searchable or not

In my Rails 3 app, I want to allow a user to specify which parts of their profile can be searchable by others. I know how to do this if I wanted to make the entire user invisible, but how can I set it up so multiple fields can be designated searchable or not separately?
More info:
In terms of functionality, I want to limit searches based on what parts of their profile a user chooses to be searchable in /settings. Parts of the profile would be, for example, #user.profile.hometown or #user.profile.current_city. I'm working off of a Combination of Railscasts #52 and Trevor Turk's tutorial to set what others can search through checkboxes in the settings.
When searchability is defined in settings, when a user searches (or filters) the /users index, what isn't hidden will be public and searchable. In terms of how this works in the DB as far as hiding table columns or grouping, I thought about hiding tables but maybe that's not the best solution. I'm as beginner as can be and hadn't really thought much about that to be honest.
Method 1 - show/hide specific columns
So, the most direct way (and this will work if there are only a handful of things you want to show/hide), is just to create a boolean column for every thing you need to show/hide. So, if you had a phone number field, you could have a column called "show_phone_number", and when true it would show it.
Method 2 - show/hide whole sections
The next level that you might need is, rather than showing/hiding particular columns, have your show/hide boolean columns something like show_contact_info, show_photos, etc. for each logical section that a user would show or hide.
Then in your view, you'd have something like:
app/views/user/show.html.erb (or .haml or whatever you're using)
....
<% if #user.show_contact_info %>
<%= render :partial => "user_contact_info", :locals => {:user => #user} %>
<% end %>
app/views/partials/_user_contact_info.html.erb
<%=h user.email %><br />
<%=h user.phone_number %><br />
<%= user.blog_url %><br />
...
Method 3 - show/hide sections based on who is viewing it
Finally (and the code here is untested, but I think you'll get the idea) let's say your site has a social structure, and you want to show information to some people, but not to others. Basically you'll need the following in some form or another:
Section visibilities (who can view what sections)
Roles (friends, followers, public, private)
a few methods to make these relationships clear/easy to understand
So, in your User model you'd have something like:
class User < ActiveRecord::Base
has_many :friends, :through => "friendships" # or whatever construct you have
has_many :followers, :through => "followings" # or whatever construct you have
has_many :profile_visibilities
...
def is_friends_with(user)
friends.include?(user)
end
def is_a_follower_of(user)
user.followers.include?(self)
end
def can_see(visibilities)
visibilities.each do |v|
v.user == self || v.is_public || can_see_because_we_are_friends(v) || can_see_because_i_follow(v)
end
end
private:
def can_see_because_we_are_friends(visibility)
visibility.is_friend && is_friends_with(visibility.user)
end
def can_see_because_i_follow(visibility)
visibility.is_follower && is_follower_of(visibility.user)
end
end
Then a class called ProfileVisibilities:
class ProfileVisibilities < ActiveRecord::Base
belongs_to :user
...
def is_public
visibility == "public"
end
def is_friend
visibility == "friends"
end
def is_follower
visibility == "followers"
def is_private
!is_public && !is_friend && !is_follower
end
end
Then a table called profile_visibilities
id | user_id | profile_section | visibility
----------------------------------------------
1 | 1 | contact_info | public # <= visible to everyone
2 | 1 | personal_info | friends # <= visible only to "friends"
3 | 1 | blog_posts | friends # <= visible to "friends"
4 | 1 | blog_posts | followers # <= ...and followers
5 | 1 | photos | friends # <= visible only to "friends"
Then in your controller, something like:
app/controllers/users_controller.rb
...
def show
#user = User.find(params[:id])
#contact_info_visibilities = ProfileVisibilities.find(:all, :conditions = ['user_id = ? AND profile_section = "contact_info"', #user.id]
#photo_visibilities = ProfileVisibilities.find(:all, :conditions = ['user_id = ? AND profile_section = "photos"', #user.id]
# ... and more for each section visibility you need
end
...
And in your view:
app/views/user/show.html.erb
...
<% if current_user.can_see(#contact_info_visibilities) %>
<%= render :partial => "user_contact_info", :locals => {:user => #user}
<% end %>
<% if current_user.can_see(#photo_visibilities) %>
<%= render :partial => "user_photos", :locals => {:user => #user}
<% end %>
...

Send to multiple recipients in Rails with ActionMailer

I'm trying to send multiple emails based on a boolean value in my database. The app is a simple scheduling app and user can mark their shift as "replacement_needed" and this should send out emails to all the users who've requested to receive these emails. Trouble is, it only every seems to send to one email. Here's my current code:
def request_replacement(shift)
#shift = shift
#user = shift.user
#recipients = User.where(:replacement_emails => true).all
#url = root_url
#recipients.each do |r|
#name = r.fname
mail(:to => r.email,
:subject => "A replacement clerk has been requested")
end
end
In the Rails guides (Action Mailer Basics) it says the following regarding multiple emails:
The list of emails can be an array of email addresses or a single string with the addresses separated by commas.
So both "test1#gmail.com, test1#gmail.com" and ["test1#gmail.com", "test1#gmail.com"] should work.
See more at: http://guides.rubyonrails.org/action_mailer_basics.html
You can just send one email for multiple recipients like this.
def request_replacement(shift)
#shift = shift
#user = shift.user
#recipients = User.where(:replacement_emails => true)
#url = root_url
emails = #recipients.collect(&:email).join(",")
mail(:to => emails, :subject => "A replacement clerk has been requested")
end
This will take all your #recipients email addresses and join them with ,. I think you can also pass an array to the :to key but not sure.
The only problem is you won't be able to use #name in your template. :(
I have the same problem. I don't know what is the deal is. I sidestep it by:
instead of calling
Mailer.request_replacement(shift).deliver
from my controller,
I'd define a class method on the mailer, and call that. That method would then iterate through the list and call deliver "n" times. That seems to work:
class Mailer
def self.send_replacement_request(shift)
#recipients = ...
#recipients.each do |recipient|
request_replacement(recipient, shift).deliver
end
end
def request_replacement(recipient, shift)
...
mail(...)
end
end
and from the controller, call
Mailer.send_replacement_request(shift)
To prevent each recipient from seeing the other email addresses:
#recipients.each{ |recipient| Mailer.request_replacement(recipient, shift).deliver }
I'm using Rails 5 and I have the same situation, the email was sent only to the last recipient but also it was sent just as plain text not as HTML email.
After trying some advices, I ended up fixing it in this way:
The mailer:
class BrochureMailer < ApplicationMailer
default from: "info#site.com"
def newsletter(sponsor, brochures_list)
#sponsor = sponsor
#brochures = brochures_list
mail(
to: #sponsor.email,
subject: "Interesting subject!"
)
end
end
The controller where the mailer is invoked:
class Admin::DashboardController < Admin::BaseController
def send_newsletter
sponsors = params[:sponsor_ids]
brochures = params[:brochure_ids]
sponsors = Sponsor.where(id: sponsors)
brochures = Brochure.where(id: brochures).to_a
# Send Newsletter email to the given Sponsors
sponsors.each do |sponsor|
BrochureMailer.newsletter(sponsor, brochures).deliver_later
end
redirect_back(fallback_location: admin_root_path, success: 'Newsletter sent!')
end
end
And in the view, something like this:
<% #brochures.each do |brochure| %>
<table width="280" border="0" cellpadding="0" cellspacing="0" align="left" valign="top" class="floater">
<tr>
<td align="center" valign="top">
<a target="_blank" href="<%= brochure_url(brochure) %>">
<img border="0" vspace="0" hspace="0" src="<%= brochure.image.blank? ? 'default.png' : brochure.image.url(public: true) %>" width="250" height="142">
<b><%= brochure.title %></b>
</a>
<br>
<%= brochure.description.truncate(60) %>
</td>
</tr>
</table>
<% end %>
And it works like a charm!
I'm not sure if this is the correct way or the most optimal way to go but just consider it as a second possibility.
I hope it could be useful for somebody else.

Rails - Getting data from a table for each iteration of a loop

Sorry for this newbie question but I cannot figure how I can do this..
I have the following City table
# Table name: cities
#
# id :integer
# name :string(255)
# country :string(255)
(note: I am not using a separate Country table as I use Geokit-rails and think it is simpler to store all Google queries in the same table. However It would be easier to have separate tables to render what I want through a belong_to/has_many association)
In my city/index view I want to loop all the cities for each countries in order to render something like:
United States
New York
San Francisco
Los Angeles
United Kingdom
London
Spain
Madrid
...
By now, What I can get is what it provided by scaffolding
Model
def index
#cities = City.all
end
View
<table>
<% for city in #cities %>
<tr>
<th><%= city.country %></th>
</tr>
<tr>
<td><%= city.name %></td>
</tr>
<% end %>
</table>
Rendering:
United States
Los Angeles
United States
New York
...
I didn't find any resource about this. I would be pleased if someone could help me (I don't know with which I have to start: find_by_ /params /each or collection?)
Thanks a lot!
The correct way to do this is to create a Country table with id and name and in your City model just keep a country_id to the country, instead of a string
so
class Country < ActiveRecord::Base
has_many :cities
end
class City < ActiveRecord::Base
belongs_to :country
end
then you can call Country.includes(:cities) and iterate over them like this in your view:
<% for country in countries %>
<%= country.name %>
<% for city in country.cities %>
<%= city.name %>
<% end %>
<% end %>
If you still want to use your way, you could do something like
#cities = City.order("country asc")
#countries = #cities.map(&:country).uniq!
<% for country in #countries %>
<%= country.name %>
<% for city in #cities %>
<%= city.name if city.country == country %>
<% end %>
<% end %>
I've had success with the group_by method:
#cities.group_by(&:country).each do |country, cities|
puts country.name
cities.each do |city|
puts "-> #{city.name}"
end
end
Output:
United States
-> New York
-> San Francisco
-> Los Angeles
United Kingdom
-> London
Spain
-> Madrid
-> Barcelona
Of course, you'll probably be doing this in an erb template, but the idea is the same:
<ul>
<% #cities.group_by(&:country).each do |country, cities| %>
<li><%= country.name %></li>
<li>
<ul>
<% cities.each do |city| %>
<li><%= city.name %></li>
<% end %>
</ul>
</li>
<% end %>
</ul>
Output:
United States
New York
San Francisco
Los Angeles
United Kingdon
London
Spain
Madrid
Barcelona
The official rails guides are an excellent place to start ;)