Action Mailer Invites Rails 3.1 - ruby-on-rails

Using Ryan Bate's RailsCasts #124 Beta Invites (as well as the updated rails 3.1 api) as a crutch, I'm trying to put together my first piece of Action Mailer functionality: inviting someone to collaborate with you on a project.
My issue is that the :recipient_email isn't getting saved in the DB and I can't see what I'm missing.
config/initializers/setup_mail.rb
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => 'blah.com',
:user_name => 'gmail username',
:password => 'gmail password',
:authentication => 'plain',
:enable_starttls_auto => true
}
ActionMailer::Base.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?
app/models/invitation.rb
class Invitation < ActiveRecord::Base
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
attr_accessor :recipient_email
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
has_one :recipient, :class_name => "User", :foreign_key => "recipient_id"
validates_presence_of :recipient_email, :on => :create, :message => "can't be blank"
validates :recipient_email, :format => email_regex
validate :recipient_is_not_registered
before_create :generate_token
def sender_name
sender.user_name
end
def sender_email
sender.email
end
private
def recipient_is_not_registered
exsisting_user = User.find_by_email(recipient_email)
if exsisting_user
errors.add :recipient_email, 'is already a member.'
else
recipient_email
end
end
def generate_token
self.token = Digest::SHA1::hexdigest([Time.now, rand].join)
end
end
app/models/user.rb (minus all the auth stuff)
class User < ActiveRecord::Base
attr_accessible :invitation_token
has_many :sent_invitations, :class_name => "Invitation", :foreign_key => "sender_id"
belongs_to :invitation
end
app/controller/invitations_controller.rb
class InvitationsController < ApplicationController
before_filter :authenticate
def new
#title = "Invite client"
#invitation = current_user.sent_invitations.new
end
def create
#invitation = current_user.sent_invitations.create!(params[:invitation])
sender_name = #invitation.sender_name
sender_email = #invitation.sender_email
if #invitation.save
Mailer.invitation(#invitation, signup_url(#invitation.token), sender_name, sender_email).deliver
flash[:success] = "Your client has been sent the email. Why not create a booking for them?"
redirect_to bookings_path
else
#title = "Invite client"
render :new
end
end
end
app/mailers/mailer.rb
def invitation(invitation, signup_url, sender_name, sender_email)
#signup_url = signup_url
#sender_name = sender_name
#sender_email = sender_email
mail(:to => invitation.recipient_email,
:subject => "Invitation to Join",
:from => #sender_email)
end
app/views/invitations/_invitation_form.html.erb
<%= form_for #invitation do |f| %>
<%= render 'shared/error_messages', :object => f.object %>
<%= f.hidden_field :email_token %>
<br />
<div class="field">
<%= f.label :recipient_email, "Client's email address" %>
<%= f.email_field :recipient_email %>
</div>
<br />
<div class="action">
<%= f.submit "Send invitation", :class => "a small white button radius" %>
</div>
<% end %>
The SQL log showing that the :recipient_email isn't getting saved
Started POST "/invitations" for 127.0.0.1 at 2011-12-14 21:27:11 +1100
Processing by InvitationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7/SGZypGXtf9ShlcjC6o8ZRj2Qe4OJTHdjis2/m3ulc=", "invitation"=>{"recipient_email"=>"users#email.com"}, "commit"=>"Send invitation"}
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.1ms) BEGIN
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'users#email.com' LIMIT 1
SQL (0.4ms) INSERT INTO "invitations" ("created_at", "recipient_email", "sender_id", "sent_at", "token", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["created_at", Wed, 14 Dec 2011 10:27:11 UTC +00:00], ["recipient_email", nil], ["sender_id", 1], ["sent_at", nil], ["token", "56fba1647d40b53090dd49964bfdf060228ecb2d"], ["updated_at", Wed, 14 Dec 2011 10:27:11 UTC +00:00]]
(10.2ms) COMMIT
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.1ms) BEGIN
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."email" = 'users#email.com' LIMIT 1
(0.1ms) COMMIT
Rendered mailer/invitation.text.erb (0.4ms)
Sent mail to users#email.com (7ms)
Date: Wed, 14 Dec 2011 21:27:11 +1100
From: admin#email.com

It's probably the attr_accessor :recipient_email line in your Invitation model. Take that line out as recipient_email is a database field, ain't it?

Related

Unpermitted parameter on has_one and belongs_to

I'm trying to update a #user.profile (with differents solutions) but get unpermitted parameters or Profile User must exist.
But in my erb console :
[3] pry(main)> User.first.id
User Load (3.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> 1
[4] pry(main)> User.first.profile.id
User Load (2.8ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
Profile Load (2.2ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT $2 [["user_id", 1], ["LIMIT", 1]]
=> 4352
What's wrong ??
{"_method"=>"patch", ....
"user"=>{"id"=>"1", "profile_attributes"=>{"user_id"=>"1", "last_name"=>"test", "id"=>"4352"}}, "commit"=>"Update", "locale"=>"fr", "controller"=>"users", "action"=>"update", "id"=>"ben"}
users_controller.rb
class UsersController < ApplicationController
def edit
#user = User.find(params[:id]
end
def update
#user = User.find(params[:id]
if #user.update_without_password(user_params)
bypass_sign_in(#user)
redirect_to edit_user_path(#user.slug), notice: t('users.user_updated')
else
flash.alert = "#{#user.errors.full_messages.join(', ')}"
render :edit
end
end
private
def user_params
params.require(:user).permit (
:id,
:email,
:pseudo,
:password,
:password_confirmation,
:current_password,
profile_attributes: %i[
id
user_id]
)
end
end
user.rb
class User < ApplicationRecord
has_one :profile, inverse_of: :user, dependent: :destroy
accepts_nested_attributes_for :profile
end
profile.rb
class Profile < ApplicationRecord
belongs_to :user, inverse_of: :profile
accepts_nested_attributes_for :user
attr_accessor :user
end
form
<%= simple_form_for #user do |f| %>
<%= f.error_notification %>
<%= f.input :id, input_html: { value: #user.id } %>
<%= f.simple_fields_for :profile do |profile| %>
<%= profile.input :user_id, input_html: { value: #user.id } %>
<%= profile.input :id, input_html: { value: #user.profile.id } %>
<% end %>
<%= f.button :submit %>
<% end %>

How to change development?

I get some error to insert following_id, then i checked the development.log:
This is my false: follower_id = nil
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 9]]
[1m[36mUser Load (1.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", "11"]]
[1m[36mSQL (3.0ms)[0m [1mINSERT INTO "relations" ("created_at", "follower_id", "following_id", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00], ["follower_id", nil], ["following_id", 11], ["updated_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00]]
I wan it to become: follower_id = 9, change between line 1 and 2
[1m[36mUser Load (0.0ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1[0m [["id", "9"]]
[1m[35mUser Load (0.0ms)[0m SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "11"]]
[1m[36mSQL (3.0ms)[0m [1mINSERT INTO "relations" ("created_at", "follower_id", "following_id", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00], ["follower_id", 9], ["following_id", 11], ["updated_at", Thu, 23 Oct 2014 07:19:22 UTC +00:00]]`
So,How can i change it to be true???Some thing wrong with my code??Please help me!
*This is my User model
class User < ActiveRecord::Base
attr_accessible :pass, :username
# Who am I following?
has_many :relations, :foreign_key => :follower_id
has_many :following, :through => :relations
# Who am I followed by?
has_many :relations, :class_name => "Relation", :foreign_key => :following_id
has_many :followers, :through => :relations
validates :username, :pass, :presence => true
validates :username, :pass, :length => { :minimum => 4 }
validates :username, :uniqueness => true
*the relation model
class Relation < ActiveRecord::Base
belongs_to :follower, :class_name => "User"
belongs_to :following, :class_name => "User"
end
*relation controller
class RelationController < ApplicationController
def create
follow = User.find(params[:relation][:following_id])
#current_user.following << follow
redirect_to follow
end
*my ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include WelcomeHelper
before_filter :set_current_user
private
def set_current_user
#current_user = User.find(session[:user_id]) if session[:user_id]
end
end
*my action view
<h2><%= #user.username%><br /></h2>
<%= #user.pass%><br />
<% if #current_user && #current_user != #user %>
<% if #current_user.following.include?(#user) %>
<%= link_to "Unfollow",
relation_path(#current_user.relation_for(#user)),
:method => :delete %>
<% else %>
<%= form_for #relation do |f| %>
<%= f.hidden_field :following_id, :value => #user.id %>
<%= f.submit "Follow" %>
<% end %>
<% end %>
<% end %>
<br>
<ul>
<% #user.following.each do |u| %>
<li><%= link_to u.username, u %></li>
<% end %>
</ul>
Followed By
<ul>
<% #user.followers.each do |u| %>
<li><%= link_to u.username, u %></li>
<% end %>
</ul>
This is my action to insert following_id
def create
follow = User.find(params[:relation][:following_id])
#current_user.following << follow
redirect_to follow
end
and my following_id has been sent
{"utf8"=>"✓",
"authenticity_token"=>"DIY42kGR9fZ54Pub+CDMuNNaHZ0aFnzSiWrkOFRBsdE=",
"relation"=>{"following_id"=>"11"},
"commit"=>"Follow"}

Nested resource wont create data, rollback transaction right after begin transaction

My problem is that a tag wont be created which is nested in posts.
I have Post which have tags nested in them. Like this
resources :posts do
resources :tags, :only => [:new, :create, :destroy]
end
In my tags controller i have this
class TagsController < ApplicationController
before_filter :authenticate_user!
def new
#post = Post.find(params[:post_id])
#tag = Tag.new
end
def create
#post = Post.find(params[:post_id])
#tag = #post.tags.build(params[:tags])
if #tag.save
flash[:notice] = "Tag created"
redirect_to #tag.post
else
flash[:error] = "Could not add tag at this time"
redirect_to #tag.post
end
end
end
new.html.erb
<%= form_for [#post, #tag] do |f| %>
<% if #tag.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tag.errors.count, "error") %> prohibited this tag from being saved:</h2>
<ul>
<% #tag.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_field :tagable_type, :placeholder => "Type" %>
</div>
<div class="field">
<%= f.text_field :tagable_id, :placeholder => "Id" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Tag model
class Tag < ActiveRecord::Base
attr_accessible :post_id, :user_id, :tagable_type, :tagable_id
validates :post_id, presence: true
belongs_to :tagable, :polymorphic => true
belongs_to :post
belongs_to :user
end
Post model
class Post < ActiveRecord::Base
attr_accessible :body, :link, :thumbnail, :title, :user_id, :youtube, :youtube_id, :website_name, :image_field
default_scope order: 'posts.active DESC'
has_many :tags, :dependent => :destroy
has_many :comments, :as => :commentable, :dependent => :destroy
belongs_to :user
end
UPDATE:
Now i can create a tag but the tagable_type and tagable_id fields are not being created for some reaseon
Started POST "/posts/18/tags" for 127.0.0.1 at 2013-06-26 15:54:14 +0200
Processing by TagsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gwpTs0Qqcrre4tH974RrfpaENGZKtSbkJx2U0H67AcM=", "tag"=>{"tagable_type"=>"Player", "tagable_id"=>"2"}, "commit"=>"Create Tag", "post_id"=>"18"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? ORDER BY posts.active DESC LIMIT 1 [["id", "18"]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "tags" ("created_at", "post_id", "tagable_id", "tagable_type", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["post_id", 18], ["tagable_id", nil], ["tagable_type", nil], ["updated_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["user_id", 1]]
(6.9ms) commit transaction
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = 18 ORDER BY posts.active DESC LIMIT 1
Redirected to http://localhost:3000/posts/18
Completed 302 Found in 15ms (ActiveRecord: 7.9ms)
There is a typo in the create() action of your TagsController:
#tag = #post.tags.build(params[:tags])
The hash used to create the tag should be params[:tag], not params[:tags].

Fields_for has_many associations not saving

So I have a deeply nested association among Polls, Questions, and Answers:
class Poll < ActiveRecord::Base
attr_accessible :description, :end_time, :start_time, :title, :user_id, :questions_attributes, :is_live
belongs_to :user
has_many :questions, :dependent => :destroy
# This is the plularized form of sms, it's not smss
has_many :sms, :through => :questions
has_many :feedbacks
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank?}, :allow_destroy => true
end
class Question < ActiveRecord::Base
attr_accessible :poll_id, :title, :answer_attributes
belongs_to :poll
has_many :answers, :dependent => :destroy
# THis is the plularized form of sms, it's not smss
has_many :sms
#If someone creates a form with a blank question field at the end, this will prevent it from being rendered on teh show page
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank?}, :allow_destroy => true
end
class Answer < ActiveRecord::Base
attr_accessible :is_correct, :question_id, :title
belongs_to :question
end
And am trying to save all objects in a single fields_for form like so.
= form_for #poll, :class=>'create-poll-form' do |f|
= f.text_field :title, :autofocus => true, :placeholder => "Poll Title"
= f.text_field :description, :placeholder => 'Description'
= f.fields_for :questions do |builder|
= render "questions/question_fields", :f => builder
= f.submit "Create Poll", :class => 'btn btn-danger'
Questions Partials
%p
= f.label :title, "Question"
= f.text_field :title
= f.check_box :_destroy
= f.label :_destroy, "Remove Question"
%p
= f.fields_for :answers do |builder|
= render "answers/answer_fields", :f => builder
Answers Partial
%p
= f.label :title, "Answer"
= f.text_field :title
= f.check_box :_destroy
= f.label :_destroy, "Remove Answer"
Yet the PollsController isn't persisting the data:
def create
binding.pry
#poll = current_user.polls.new(params[:poll])
# #poll = Poll.create(params[:poll])
binding.pry
#poll.save!
redirect_to root_path
end
def new
#poll = Poll.new
1.times do
question = #poll.questions.build
2.times {question.answers.build}
end
end
Any tips here would be amazing, I've been working on this for a bit and it's stumping me! Thanks in advance!
Also here's the server log:
Started POST "/polls" for 127.0.0.1 at 2013-06-06 20:14:47 -0400
Processing by PollsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hk+KuNsTLx3sH9pE7Mf8XETGsmxTsRN4/tWUBn3CIVE=", "poll"=>{"title"=>"Testing 1-2-1-2", "description"=>"Up on the mic", "questions_attributes"=>{"0"=>{"title"=>"Cake or Death?", "_destroy"=>"0", "answers_attributes"=>{"0"=>{"title"=>"Cake", "_destroy"=>"0"}, "1"=>{"title"=>"Death", "_destroy"=>"0"}}}}}, "commit"=>"Create Poll"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Question Load (0.5ms) SELECT "questions".* FROM "questions" WHERE "questions"."poll_id" IS NULL
(0.3ms) BEGIN
SQL (47.6ms) INSERT INTO "polls" ("created_at", "description", "end_time", "is_live", "start_time", "title", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["created_at", Fri, 07 Jun 2013 00:16:46 UTC +00:00], ["description", "Up on the mic"], ["end_time", nil], ["is_live", nil], ["start_time", nil], ["title", "Testing 1-2-1-2"], ["updated_at", Fri, 07 Jun 2013 00:16:46 UTC +00:00], ["user_id", 1]]
(0.8ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 170668ms (ActiveRecord: 54.9ms)
I'm not sure if this is the problem but in your
class Question < ActiveRecord::Base
attr_accessible :poll_id, :title, :answer_attributes
but in your log file it has
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hk+KuNsTLx3sH9pE7Mf8XETGsmxTsRN4/tWUBn3CIVE=", "poll"=>{"title"=>"Testing 1-2-1-2", "description"=>"Up on the mic", "questions_attributes"=>{"0"=>{"title"=>"Cake or Death?", "_destroy"=>"0", "answers_attributes"=>{"0"=>{"title"=>"Cake", "_destroy"=>"0"}, "1"=>{"title"=>"Death", "_destroy"=>"0"}}}}}, "commit"=>"Create Poll"}
The difference being :answers_attributes, rather than :answer_attributes i.e. answer vs answer*s
This may be causing the data to be thrown away.

Nested form not saving in rails 3.1

Noob question, I'm sure, but I can't seem to find my mistake. SymptomSets are saving w/ the proper user_id, but the nested symptoms disappear. Note that the user model structure is identical to that in the Rails Tutorial (save that it has_many :symptom_sets)
Models:
class SymptomSet < ActiveRecord::Base
attr_accessible :symptoms, :symptoms_attributes
belongs_to :user
has_many :symptoms, :dependent => :destroy
accepts_nested_attributes_for :symptoms, allow_destroy: true
end
class Symptom < ActiveRecord::Base
attr_accessible :name, :duration, :symptom_set_id
belongs_to :symptom_set
end
Controller:
class SymptomSetsController < ApplicationController
before_filter :signed_in_user, only: [:create, :new]
def new
#symptom_set = SymptomSet.new
3.times do
symptom = #symptom_set.symptoms.build
end
end
def create
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
if #symptom_set.save
flash[:success] = "Symptoms submitted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
And the View:
<%= simple_form_for #symptom_set, :html => { :class => 'form-inline' } do |f| %>
<%= f.fields_for :symptoms do |builder| %>
<%= render 'symptom_fields', f: builder %>
<% end %>
<div class="actions"><%= f.submit %></div>
<% end %>
And the partial:
<%= f.input :name,
:collection=> ["Cough", "Fever", "Headache", "Lethargy"],
label: "Symptom",
prompt: "Select a symptom",
:input_html => { :class => "span3" }%>
<%= f.input :duration,
:collection => 1..14,
label: "Duration",
prompt: "How many days?" %>
finally, the rails server console outputs the following:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"s7ksuk40M2r76Nq4PGEEpTpkCECxFniP4TtpfSHszQk=", "symptom_set"=>{"symptoms_attributes"=>{"0"=>{"name"=>"Cough", "_destroy"=>"false", "duration"=>"2"}, "1
"=>{"name"=>"Fever", "_destroy"=>"false", "duration"=>"2"}, "2"=>{"name"=>"", "_destroy"=>"1", "duration"=>""}}}, "commit"=>"Create Symptom set"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" ='OH6_nuvySNjd6AbTuDunsw' LIMIT 1
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "symptom_sets" ("created_at", "updated_at", "user_id") VALUES ($1, $2, $3)
RETURNING "id" [["created_at", Tue, 05 Feb 2013 21:12:07 UTC +00:00], ["updated_at", Tue, 05 Feb 20
13 21:12:07 UTC +00:00], ["user_id", 1]]
(1.1ms) COMMIT
I'd try changing:
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
to:
#symptom_set = current_user.symptom_sets.new(params[:symptom_sets])
I don't know if build would work there.
And also checking the params on the terminal log if it is called symptom_sets and if it's sending the parameters of nested form attributes.
EDIT:
I Really think your param's name would be symptom_set in singular. check that.

Resources