I am trying to setup a system where if User A is reading a status from User B and clicks 'I'm interested' it will send a pre default message to User B's inbox (create new record in the Message table). This is sort of like on social networks where users sends a 'wink' to another user. I was able to do a similar setup for another section on the app that works, but I can't get this 'wink' feature to work. After the user clicks 'I'm interested', that link should no longer be available to the user for that status. I get a undefined method 'interested= error.
Intrigued Controller:
def create
#intrigue = current_user.intrigues.build(intrigue_params)
end
def destroy
#intrigue.destroy
end
def repost
#intrigue = Intrigue.find(params[:id]).repost(current_user)
end
#Need help with below code
def interested
#intrigue = User.find(params[:id])
#message = Message.create(:subject => "#{user_id} is Interested in you",
:sender_id => #user_id,
:recipient_id => #intrigue.user_id,
:body => "I saw your date and I'm interested")
#intrigue.message = #message
render :new, alert: 'Your message was sent.'
end
Routes:
resources :intrigues do
member do
post :repost
post :interested
end
end
I added has_one :intrigue to the Message model.
I added belongs_to :message to the Intrigue model.
The intrigues table has the following columns: id, content, user_id
The messages table has the following columns: id, sender_id, recipient_id, subject, body
Remove the line #intrigue.message = #message
Your sender id and recipient id are incorrect also.
def interested
#intrigue = User.find(params[:id])
#intrigue = current_user
#recipient = Intrigue.find(params[:id])
#message = Message.create(:subject => "Someone is Interested in you",
:sender_id => #intrigue.id,
:recipient_id => #recipient.user_id,
:body => "I saw your date and I'm interested")
render :new, alert: 'Your message was sent.'
end
That will have it working with no errors. I would also add a redirect.
Related
I'm new to rails , and I have a problem with the nested forms and all of that.
I have a User model, and an Organization model.
When I want to create a user, I want to specify from which organization does he comes from.
Either the organization name is already in the database or if it's not, I want to create a new record and associate that record the User model.
I have hard time understanding all the relations (many-to-many etc) implications in the rails framework, but so far I've got this.
model/organization.rb
class Organization < ActiveRecord::Base
has_many :user
validates_presence_of :name
end
model/user.rb (short)
class User < ActiveRecord::Base
belongs_to :organization
accepts_nested_attributes_for :organization
#####
end
From this, in the console, I can create user and specify and organization name , and it will create a new record for the user and a new record for the organization.
The problem is that it creates a new organization each time.
I want to be able to associate an already existing organization to a new user.
I can get the list of organization with things like typeahead.js for the form, so the name will be the same when the user selects one. But I don't know how to relate the two (the newly created user and already existing organization).
I thought of putting a hidden field with the id of the organization, and check in the controller if this id exists. If it does, put this id, if it doesn't create a new one. But I don't even know how to do this. In the console, when I update the attributes of a user, for example , with an organization_id = 3 which exists :
u.update_attributes( :organization_attributes => { id: 3 } )
It rejects saying he didn't find a user with ID=... with Organization.id = 3 ...
I don't understand.
I suppose since this is a common case, that this should be easy , but it's messing with my head.
If someone is willing to explain to me, I'd be very grateful.
Thank you.
EDIT
i've just tried something in my controller but that doesn't work either.
def create
#user = User.new(user_params) # :user object built from user inputform
org = Organization.find_by(name:user_params[:organization_attributes][:name])
if org
#user.organization.id = org.id
end
if #user.save
# signin the user (token etc)
sign_in #user
flash[:success] = "Registration sucessfull !"
redirect_to #user
else
render 'new'
end
end
+user_controller (strong params)
def user_params
params.require(:user).permit(:lname,:email,:fname,:password,:password_confirmation,
:gender,:role,:display_private,:link_li,:country,:city,:phone,:hobbies,
:avatar,:org_name, :organization_attributes => [ :id, :name])
end
+form.html.erb
<%= u.fields_for :organization do |o| %>
<%= o.label "Organization" %>
<!-- PUT ORGA -->
<%= o.text_field :name, class:"form-control" %>
<% end %>
I would write a custom method for this:
#in User
def organization_name
(org = self.organization) && org.name
end
def organization_name=(name)
if org = Organization.find_by_name(name)
self.organization = org
else
self.organization = Organization.create(:name => name)
end
end
Now, because you've got a getter and setter method (ie two methods with the same name, apart from the = sign), you can treat organization_name like an attribute of User and put it in a form field like
f.input :organization_name
The input will get the current value from #user.organization_name and will call #user.organization_name= with the new value.
First take away the accepts_nested_attributes from the model.
Then in your controller you should do something like:
def create
#user = User.new(user_params) # :user object built from user inputform
org = Organization.where(name: user_params[:organization_attributes][:name]).first || Organization.create(name: user_params[:organization_attributes][:name])
#user.organization = org
if #user.save
# signin the user (token etc)
sign_in #user
flash[:success] = "Registration sucessfull !"
redirect_to #user
else
render 'new'
end
end
In your app/model/user.rb
def self.create(name, attribute1, ... ,organization)
user = User.new(:name => name, :atr_1 => attribute_1, ....:atr_n => attribute_n)
user.organization = organization
raise "user not created" if !user.save
user
end
In users_controller.rb
def create
org = Organization.find params['organization'] #expecting the param to be Organization#id
user = User.create(params['name'], ..., org)
render :json => {:message => "user created"}
end
Currently I have ActionMailer send an email when a user registers, and I generate a random :sign_in_token with the user.
How can a user then click on the link sent to his email and update the users :registration_complete boolean value to TRUE?
Currently, I am able to send the link and generates a random token, but I don't know how to update the boolean value through the email.
MODELS
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :sign_in_token,
:registration_complete
###This generates my sign_in_token
def generate_sign_in_token
self.sign_in_token = Digest::SHA1.hexdigest([Time.now, rand].join)
end
end
CONTROLLER
def create
#user = RegularUser.new(params[:regular_user])
if #user.save
###Sends the User an email with sign_in_token
UserMailer.registration_confirmation(#user, login_url+"/#{#user.sign_in_token}").deliver
flash[:success] = "Please Check Your Email to Verify your Registration!"
redirect_to (verifyemail_path)
else
render 'new'
end
end
USER_MAILER
def registration_confirmation(user, login_url)
#login_url = login_url
#user = user
mail(:to => "#{user.name} <#{user.email}>", :subject => "Welcome to APP")
end
VIEWS
###Redirects User to Login Page, But how do i connect it to my activate method?
<%= link_to "Complete Registration", #login_url %>
ROUTES
match '/login/:sign_in_token', :to => 'sessions#new'
When they click a link, it takes them to a controller with an action of set_complete using a GET request, which sets the boolean value.
Something like:
def set_complete
user = User.find(params[:user])
user.update_attribute(registration_complete => true)
redirect_to login_path # or whatever your login url is...
end
For the controller action and something like this for the link:
<a href="example.com/registrations/set_complete?user=1" />
Here is a sample of what might go in the routes file:
get "/users/set_complete", :to => "users#set_complete"
You'd probably need to set the user id to whatever you want using erb, andmake a few other app-specific customizations, but this is the general idea.
Hope this helps!
I am new to rails. I am having problem in mail sending to multiple models. Our project contains parent,teacher and student models.each module having number of users(student,parent,teacher). And also I am having three check box.that is student,teacher,parent.when I click student and teacher.the mail should be sent to all teachers and all students.
If I want send a mail to teacher and also student means ,the problem behind this, mail was sending only to teacher not student. how to solve this problem.and I included my coding.
Controller
def send_news_letter
if params[:announcement].present?
#announcement = Announcement.find(params[:announcement].keys).first
end
if params[:students].present? and params[:teachers].present?
#student = Student.pluck(:email)
#teacher = Teacher.pluck(:email)
UserMailer.send_multiple_email(#student,#teacher,#announcement).deliver
redirect_to announcements_url, :notice => "Newsletter Delivered Successfully" a
end
end
Usermailer.rb
class UserMailer < ActionMailer::Base
default to: Proc.new {Teacher.pluck(:email)},
to: Proc.new {Student.pluck(:email)},
from: "from#example.com"
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.user_mailer.password_reset.subject
#
def password_reset(user)
#user = user
mail :to => user.email, :subject => "Password Reset"
end
def send_multiple_email(user,employee,announcement)
#user = user
#employee = employee
#announcement = announcement
mail :subject => "Deliver"
end
end
Please help me.Thanks in advance.
First, in your controller I would store all addresses in one array:
#emails = []
if params[:students].present?
#emails += Student.pluck(:email)
end
if params[:teachers].present?
#emails += Teacher.pluck(:email)
end
if params[:parents].present?
#emails += Parent.pluck(:email)
end
UserMailer.send_multiple_email(#emails,#announcement).deliver
And then in your mailer change to this:
def send_multiple_email(emails,announcement)
#announcement = announcement
emails.each do | address |
mail :to => address, :subject => "Deliver"
end
end
Please note, that if you're referencing your models in the mailer template (such as "Hi <%= #user.name %>!") then you need to load the whole model object. Now you're just using pluck to get a list of all the addresses you want to send to. To get the whole model, change pluck(:email) to all in your controller and change your mailer to reference the attributes in that model instead. This also means your three models need to have the same attribute names (at least the ones you intend to use in the mailer).
Hope it makes sense.
I have a User model (with Devise), and a Post model that belongs to the user. I used this railscast (pro) to send the User an email after creating an account
I created a "NewPostMailer"
This is my mailer:
class NewPostMailer < ActionMailer::Base
default :from => "email#gmail.com"
def new_post_email(user)
#user = user
#url = "http://localhost.com:3000/users/login"
mail(:to => user.email, :subject => "New Post")
end
end
My posts_controller:
def create
#post= Post.new(params[:post])
respond_to do |format|
if #deal.save
NewPostMailer.new_post_confirmation(#user).deliver
format.html { redirect_to #post, notice: 'Post was successfully created.' }
post.rb
after_create :send_new_post_email
private
def send_new_post_email
NewPostMailer.new_post_email(self).deliver
end
What do I have to change to send the User an email after he creates a Post. Thanks.
Create another mailer (http://railscasts.com/episodes/206-action-mailer-in-rails-3)
class YourMailerName < ActionMailer::Base
default :from => "you#example.com"
def post_email(user)
mail(:to => "#{user.name} <#{user.email}>", :subject => "Registered")
end
end
In your Post model
after_create :send_email
def send_email
YourMailerName.post_email(self.user).deliver
end
Sending an email is very slow so think about putting this in a background job.
You should be able to use a fairly similar method to do this. First, create an after_create callback in your Post model, with something like:
after_create :send_user_notification
def send_user_notification
UserMailer.post_creation_notification(user).deliver
end
You will need to make sure that there is a relationship between the user and the post, and create the post_creation_notification method in your UserMailer, the same way you made your old one. It might also be worth pointing out that just blindly firing off emails like this isn't necessarily the best way to do this. Not only does it add extra unnecessary time to a request, but it also doesn't fail in a gracefully recoverable fashion. You may wish to explore adding the emails to be sent to a queue (like this, for example) to be processed, with a cron job or something, if the site you are creating will see anything other than very light usage.
I have created a Ruby on Rails application where users can track workouts. The can do so either privately or publicly. On workouts which are public ( workout.share == 1 ) I allow users to comment. When a comment is created on a workout, the workout owner is notified via email. That all works great.
I am now looking for some advice on the best way to allow users who have commented on a workout, to also be notified via email. Here is an example.
User A creates Workout 1. User B comments on Workout 1 and User A receives an email notification. User C also comments on Workout 1 and both User A and User B receive email notifications.
What is the best way to tell my application to loop through all the users who have commented on Workout 1 and send an email to them?
Currently I am sending an email to the workout owner with the following code in the comments_controller (I realize this could be cleaner code):
class CommentsController < ApplicationController
...
def create
#workout = Workout.find(params[:workout_id])
#comment = #workout.comments.build(params[:comment])
#comment.user = current_user
respond_to do |format|
if #comment.save
if #comment.workout.email_notification == 1
#comment.deliver_comment_notification_mail!
format.html { redirect_to( projects_path) }
format.js
else
format.html { redirect_to( projects_path) }
format.js
end
else
end
end
end
...
and in comment_mailer.rb
def comment_notification_mail(comment)
subject "Someone commented on your Workout"
recipients("#{comment.workout.user.username} <#{comment.workout.user.email}>")
from("foobar")
body :comment => comment,
:commenter => comment.user,
:workout => comment.workout,
:commentee => comment.workout.user,
:workout_url => workout_url(comment.workout),
:commenter_url => user_url(comment.user)
end
To find out a workout owner and commenter is not a hard job. My suggestions are:
move the code of sending email in your controller to your model, using #after_create, eg:
class Comment < ActiveRecord::Base
#...
after_create :notify_subscribers
def subscribers
(self.workout.commenters << self.workout.owner).uniq
end
def notify_subscribers
#... implemented below
end
end
using delayed_job or other tools to put the email sending job to background, or the request would be blocked until all the emails has been sent. eg, in the #notify_owner_and_commenter method
def notify_subscribers
self.subscribers.each do |user|
CommentMailer.send_later :deliver_comment_notification_mail!(self, user)
end
end
Then you need to refactor you #deliver_comment_notification_mail! method with two arguments.
Delayed job ref: https://github.com/tobi/delayed_job
From my POV, it's all the work of the mailer. I'd just rewrite the comment_notification_mail to something more neutral (which could speak to workout owner and commenters).
Then something like:
def comment_notification_mail(comment)
recs = [comment.workout.user]
recs << comment.workout.comments(&:user)
recs -= comment.user
subject "Someone commented on your Workout"
recipients(recs.inject('') { |acc, r| "#{r.username} <#{r.email}>" })
from("foobar")
body :comment => comment,
:commenter => comment.user,
:workout => comment.workout,
:commentee => comment.workout.user,
:workout_url => workout_url(comment.workout),
:commenter_url => user_url(comment.user)
end
Of course, if mails are not supposed to be public, send by bcc ;)