Cart Checkout >> Send an Email with Cart Items included - ruby-on-rails

I have an "Add To Cart" function working fine based on Sessions so no user is currently logged in.
Here's the Model
class Cart < ActiveRecord::Base
has_many :tutors
def add_tutor(tutor_id)
tutor = Tutor.find(tutor_id)
if tutor
self.tutors << tutor
end
save
end
end
Here's the Controller
class CartsController < ApplicationController
def show
#cart = current_cart
end
def add_to_cart
current_cart.add_tutor(params[:tutor_id])
redirect_to tutors_path
end
end
What i would like to do is when the user checkouts, they will be redirected to a page with a simple form requesting for their name/email/phone-number, and when that email is sent to me, it includes the items in their cart.
I am currently using gem 'mail_form' and this is what i have set-up so far.
Model checkout.rb
class Checkout < MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)#([\w\-]+\.)+([\w]{2,})\z/i
attribute :hp, :validate => true
def headers
{
:subject => "Tutor Checkout",
:to => "xxx#xxx.com"
}
end
end
Controller checkouts_controller.rb
class CheckoutsController < ApplicationController
def new
#checkout = Checkout.new
end
def create
#checkout = Checkout.new(params[:checkout])
#checkout.request = request
if #checkout.deliver
flash[:notice] = 'Thank you! We will be in touch with you shortly!'
else
flash[:error] = 'There was an error in sending your message!'
render :new
end
end
end
and under views/checkouts/new.html.erb its just a form requesting for their information.
What i really have no idea on where to start is creating the association between Carts and Checkouts and how do i even include the items in the cart to be sent along with the email?
Any help or advice would be greatly appreciated! Thank you!

Related

Want to limit amount of posts in rails

So I am making a site where users can only submit a post once, and then the "new post" button goes away forever.
I would also like to put a limit on the overall amount of posts. So, only the first 100 or so people can actually post.
I used rails generate scaffold to build the posting system.
I don't know where to start.
Thanks!
You can either create a constant if all user will have the same limit, or add a field in your user record if you plan for each user to have different limits.
Then you create a validator which check the number of existing posts and forbid creation of new posts if the limit is reached
More info in rails guide: http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
An alternative approach is using a policy object. Here's how I would approach this using Pundit.
Updated:
app/models/post.rb
class Post < ActiveRecord::Base
belongs_to :user
def self.limit_exceeded?(max = 100)
count >= max
end
end
app/models/user.rb
class User < ActiveRecord::Base
has_one :post
end
app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def create?
!user_has_post? && space_to_post?
end
private
def user_has_post?
user.post.present?
end
def space_to_post?
!Post.limit_exceeded?
end
end
app/controllers/posts_controller.rb
class PostsController < ApplicationController
def show
#post = Post.find(params[:id])
end
def new
#post = Post.new
end
def create
authorize(:post)
#post = current_user.build_post(post_params)
if #post.save
redirect_to #post, notice: "Your post was created!"
else
render :new
end
end
private
def post_params
params.require(:post).permit(:message)
end
end
app/view/posts/new.html.erb
<% if policy(:post).create? %>
<%= form_for(#post) do |form| %>
<%= form.text_area :message %>
<%= form.submit "Post" %>
<% end %>
<% else %>
You cannot post.
<% end %>
This code assumes the user is authenticated. If you haven't incorporated authentication, you'll need to use a gem for that, or roll your own implementation. I'd recommend Devise or Clearance.
Good luck!

Unable to access controller variables in model

I have following controller
class PaypalOrdersController < Spree::BaseController
def new
#paypal_order = PaypalOrder.new
end
def create
#order1 = current_order
#paypal_order = PaypalOrder.new(params[:paypal_order])
if #paypal_order.save
if #paypal_order.purchase
render :action => "success"
else
render :action => "failure"
end
else
render :action => "new"
end
end
end
and the corresponding model is:
class PaypalOrder < ActiveRecord::Base
require 'paypal_payment'
belongs_to :order
attr_accessor :card_number, :card_verification
validate :validate_card, :on => :create
def purchase
orderHash = #order1.clone
paypalHash = #paypal_order.clone
PaypalPayment.new(orderHash, paypalHash)
end
private
def validate_card
#some code
end
def credit_card
#some code
end
end
When the purchase method is triggered I'm getting the error cannot clone nil class. On debugging I found that #order1 and #paypal_order both are nil in the purchase method. I am not sure why this is happening. Please can someone explain.
Thanks
controller:
PaypalOrder.purchase #order1, #paypal_order
model:
def self.purchase order, paypal_order
orderHash = order.clone
paypalHash = paypal_order.clone
PaypalPayment.new(orderHash, paypalHash)
end
edit:
How do you pass data from a controller to a model with Ruby on Rails?
Try this
controller
if #paypal_order.purchase #order1
model
def purchase order1
orderHash = order1.clone
paypalHash = self.clone
PaypalPayment.new(orderHash, paypalHash)
end

PayPal IPN Send Email

I have a controller that handles PayPal's IPN callback. I want to mark an attendee as 'paid' and send them a confirmation email if they've successfully paid.
The mark paid action is working but the email is not sending.
Here's my controller:
class PaymentNotificationsController < ApplicationController
protect_from_forgery :except => [:create]
def create
PaymentNotification.create!(:params => params, :attendee_id => params[:invoice], :status => params[:payment_status], :transaction_id => params[:txn_id])
if params[:payment_status] == 'Complete'
#attendee = Attendee.find(params[:invoice])
## Working
#attendee.update_attribute(:paid, Time.now)
## Not Working
UserMailer.welcome_email(#attendee).deliver
end
render nothing: true
end
end
Here's my user_mailer file:
class UserMailer < ActionMailer::Base
default from: 'example#email.com'
def welcome_email(user)
#user = user
email_with_name = "#{#user.first_name} #{#user.last_name} <#{#user.email}>"
#url = 'http://example.com'
mail(
to: email_with_name,
subject: 'Welcome to Yadda Yadda'
)
end
end
Here's the weird thing, in another controller that doesn't have PayPal the mailer works:
class VendorsController < ApplicationController
def create
#vendor = Vendor.new(vendor_params)
if #vendor.save
UserMailer.welcome_email(#vendor).deliver
redirect_to vendor_success_path
else
render 'new'
end
end
end
I am pulling your answer out of your question and posting it here for future reference.
This takes two actions (mark paid and send mail). It has been moved to the model as an after_create method.
Here's the model:
class PaymentNotification < ActiveRecord::Base
...
after_create :mark_attendee_paid
private
def mark_attendee_paid
if status == 'Completed'
attendee.update_attribute(:paid, Time.now)
UserMailer.welcome_email(attendee).deliver
end
end
end

Automatically Create Guest User With Rails

I followed Railscast #393 to implement guest users into my application. The only problem I'm having with this approach is that it requires the user to still click a button to create the user (albeit without signing up). My goal is to have this occur automatically, but without happening every time the page is reloaded or visited again. I'm at a loss on how to go about this.
user_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = params[:user] ? User.new(params[:user]) : User.new_guest
if #user.save
current_user.move_to(#user) if current_user && current_user.guest?
session[:user_id] = #user.id
redirect_to root_url
else
render "new"
end
end
end
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :provider, :uid, :email
has_many :posts, :dependent => :destroy
has_many :comments, :dependent => :destroy
def self.new_guest
new { |u| u.guest = true }
end
def move_to(user)
posts.update_all(user_id: user.id)
comments.update_all(user_id: user.id)
end
end
application.html.erb
<ul>
<li><%= button_to "Try it for free!", users_path, method: :post %></li>
</ul>
I can provide any additional information necessary to help answer this question.
You could potentially handle this in a before_filter, but you'd want to consider that you'd be creating a new guest user any time that anyone or anything (Google bot, for instance) requests a page from your site without an existing session. Requiring some sort of user action to kick it off is probably a good thing. That being said, if you really wanted to do it you could do something like this in your ApplicationController:
before_filter :create_guest_if_needed
def create_guest_if_needed
return if session[:user_id] # already logged in, don't need to create another one
#user = User.new_guest
#user.save
session[:user_id] = #user.id
# do anything else you need here...
end

How to add current_user to user_id to form_for in rails?

I have a form for creating materials (title, description and content - all basic). The form saves these details just fine but it doesn't save the user_id, which should be the user_id of the current_user. How do I do this? It must be easy but nothing has worked so far.
def create
#material = Material.new(params[:material])
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
def create
#material = Material.new(params[:material])
#material.user_id = current_user.id if current_user
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
There are a few different ways to do it depending on how you have your application setup. If there is a relationship between the user and materials (User has many materials), you could use that in your controller:
def create
#material = current_user.materials.new(params[:material])
# ...
end
If you don't have that relationship, I would still recommend setting it in the controller as opposed to a hidden field in the form. This will be more secure because it won't let someone tamper with the user id value:
def create
#material = Material.new(params[:material].merge(user_id: current_user))
# ...
end
Assuming you are saving the login users's object in the current_user following will work for you
#material = Material.new(params[:material])
#material.user_id = current_user.id
if #material.save
With Rails 5 and parameters needing to be permitted before objects are created, this is the simplest way to merge the current_user into the params, kudos to #Peter Brown in his answer:
def create
#discussion = current_user.materials.new(new_material_params)
# ...
end
private
def new_material_params
params.require(:material).permit(:title, :description,: content)
end
If you have nested object creation using accepts_nested_attributes_for, you need to manually merge deep into the association parameters:
class User < ApplicationRecord
has_many :discussions # Used to associate User with Discussion later
end
class Comment < ApplicationRecord
belongs_to :user
end
class Discussion < ApplicationRecord
belongs_to :user
has_many :comments
accepts_nested_attributes_for :comments
end
class DiscussionsController < ApplicationController
def create
# Merge the params[:discussion][:user_id] by using the relationship's #new
#discussion = current_user.discussion.new(new_discussion_params)
end
private
# Sanitized params for creation, not editing
def new_discussion_params
params.require(:discussion)
.permit(:title, :user_id,
comments_attributes: [:id, :content, :discussion_id, :user_id])
.tap do |discussion_params|
# Require the association parameters, and if they exist,
# set :user_id for each.
discussion_params.require(:comments_attributes).each do |i, comment|
comment.merge!(user_id: current_user.id)
end
end
end
end
Heads up: Setting (or overwriting!) what will be params[:discussion][:comments_attributes]["0"][:user_id] works fine for creation. But if you allow editing deep hierarchies in addition to creation, make sure you don't accidentally overwrite all the :user_ids with the current user.

Resources