get last insert id from after_create callback - ruby-on-rails-3

my controller
new_task = {:user_id => params[:user_id],:task => params[:task] }
work = Work.new new_task
if work.valid?
work.save!
if !params[:sub].nil?
new_sub = {:activity => self.activity.id,:sub_task => "something etc" }
sub_task = SubTask.new new_sub
sub_task.save!
end
end
My Model
attr_accessible :user_id, :task, :created_at, :updated_at
after_create :add_activity
def add_activity
new_activity = {:user_id => self.user_id,:text => "new task" }
user_activity = Activity.new new_activity
user_activity.save!
end
how i can get last inserted ID of activity form after_create callback. self.activity.id is not working for me

def last_activity
#last_activity || (Activity.where(:user_id => self.user_id).order("id").last if user_id)
end
def add_activity
new_activity = {:user_id => self.user_id,:text => "new task" }
user_activity = Activity.new new_activity
user_activity.save!
#last_activity = user_activity
end
self.last_activity.id

Related

rails-rspec uniqueness validation using accepts_nested_attributes_for

My models relationship like
class Cart < ActiveRecord::Base
has_many :cart_items, :inverse_of => :cart, :dependent => :destroy
accepts_nested_attributes_for :cart_items, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
validates_associated :cart_items
validates :cart_name, :presence => {:message => "Must be filled" }
end
class CartItem < ActiveRecord::Base
belongs_to :cart, :inverse_of => :cart_items
validates :cart_item_no, :presence => {:message => "Must be filled"}, :uniqueness => {:message => "Already exists" }
end
factories.rb
FactoryGirl.define do
factory :cart do
cart_name "sample"
factory :cart_with_cart_items do
after(:build) {|cart|
2.times { cart.cart_items.build(attributes_for(:cart_item)) }
}
after(:create) {|cart|
cart.cart_items.each {|cart_item| cart_item.save! }
}
end
end
factory :cart_item do
cart_item_no 1
cart
end
end
Below test case always fails
it "should not be valid with same cart_id" do
cart = FactoryGirl.build(:cart_with_cart_items)
cart.should_not be_valid
end
then I exploring in console, validation always returning true with same *cart_item_no* twice in cart_items by the example of below code.
cart = Cart.new(:cart_name => "yyy")
=> #<Cart id: nil, cart_name: "yyy">
2.times { cart.cart_items.build(:cart_item_no => 1000) }
=> 2
cart.cart_items
=> [#<CartItem id: nil, cart_item_no: 1000>, #<CartItem id: nil, cart_item_no: 1000>]
cart.valid?
=> true
cart.save!
=> true
Is this rails problem?
how to solve test case?
Uniqness validation checks against the database only. In your case, you have two cart_items that conflict with each other but not with any record in the database, so individually, both are valid, which is why your validations passes.
You could add a custom validation in your Cart class (not tested):
validates :unique_cart_items
def unique_cart_items
unless cart_items.collect(&:cart_item_no).uniq.size < cart_items.size
# set some error attribute here
end
end
This compares the number of unique cart_item_no values to the number of cart_items. If they are not the same, there's a duplicate cart_item_no.

Actionmailer Rails 3

I have added a contact form to my site and am having a problem, when the message is sent I get my flash message, "successfully sent", however the email never arrives in my inbox. I am in development mode at the moment and my app/config file looks like this
class Application < Rails::Application
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.raise_delivery_errors = true
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => "gmail.com",
:user_name => "myemail#gmail.com",
:password => "example",
:authentication => :plain,
:enable_starttls_auto => true
}
config.action_mailer.default_url_options = {
:host => "gmail.com"
}
My contact Controller is like this
def new
#message = Message.new
end
def create
#message = Message.new(params[:message])
if #message.valid?
NotificationsMailer.new_message(#message).deliver
redirect_to(root_path, :notice => "Message was successfully sent.")
else
flash.now.alert = "Please fill all fields."
render :new
end
end
end
and finally my Notification Mailer
class NotificationsMailer < ActionMailer::Base
default :from => "myemail#gmail.com"
default :to => "myemail#gmail.com"
def new_message(message)
#message = message
if message.file
attachment_name = message.file.original_filename
attachments[attachment_name] = message.file.read
end
mail(:subject => "[myemail#gmail.com] #{message.subject}")
end
end
Am I missing anything obvious here as I have implemented this in another site which worked fine, just cant figure out what is going on
Any help appreciated
I know you set it in your app/config.rb, but I would ensure config.action_mailer.perform_deliveries isn't being overridden in your config/environments/development.rb

Hw do i render a partial in rails 3.0 using ajax?

I want to use ajax in my application here is my problem :
I have a income voucher controller and model which receives incomes from various sources.
for this i have a payment_mode model with card, cheque and internet_banking payment option here is my code:
From model:
income_voucher
class IncomeVoucher < ActiveRecord::Base
has_one :payment_mode, :foreign_key => :voucher_id
end
** payment_mode:**
class PaymentMode < ActiveRecord::Base
belongs_to :transactionable, :polymorphic => true
belongs_to :receipt_voucher
end
card_payment:
class CardPayment < ActiveRecord::Base
has_one :payment_mode, :as => :transactionable, :dependent => :destroy
end
similar in cheque and Internet banking model .
My controller:
income_vouchers_controller:
class IncomeVouchersController < ApplicationController
def new
#income_voucher = IncomeVoucher.new
#invoices = current_company.invoices
#income_voucher.build_payment_mode
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #income_voucher }
end
end
def create
#income_voucher = IncomeVoucher.new(params[:income_voucher])
transaction_type = params[:transaction_type]
payment_mode = nil
if transaction_type == 'cheque'
payment = ChequePayment.new(params[:cheque_payment])
payment.amount = #income_voucher.amount
elsif transaction_type == 'card'
payment = CardPayment.new(params[:card_payment])
payment.amount = #income_voucher.amount
elsif transaction_type == 'ibank'
payment = InternetBankingPayment.new(params[:internet_banking_payment])
payment.amount = #income_voucher.amount
else
payment = CashPayment.new
payment.amount = #income_voucher.amount
end
payment_mode = PaymentMode.new
payment_mode.transactionable = payment
#income_voucher.payment_mode = payment_mode
respond_to do |format|
if #income_voucher.save
format.html { redirect_to(#income_voucher, :notice => 'Income voucher was successfully created.') }
format.xml { render :xml => #income_voucher, :status => :created, :location => #income_voucher }
else
format.html { render :action => "new" }
format.xml { render :xml => #income_voucher.errors, :status => :unprocessable_entity }
end
end
end
In my form i did this:
<%= render :partial => "card_payment" %>
<%= render :partial => "cheque_payment" %>
<%= render :partial => "internet_banking_payment" %>
friend till now i am rendering my partials simply as we do in rails but now i want to do this using ajax. I hope you guy's have done this earlier.
thanks
It's simple:
In your javascript (on page, for example:
$.ajax({
url: "your_path",
data: { //params if needed
your_param_name: param,
your_param_name2: param2
}
});
In your routes:
match 'your_path' => 'y_controller#y_method'
In y_controller:
def y_method
# do smth with params[:your_param_name] if needed
respond_to do |format|
format.js
end
end
In your y_method.js.erb:
$('#your-div').html('<%= raw escape_javascript render("cart_payment") %>'); //instead html() may be append()

Authlogic - how to set password_confirmation only for update?

I am trying to set up the password confirmation only on the page, where the user change his password.
My model looks this way:
class User < ActiveRecord::Base
attr_accessor :password_confirmation
acts_as_authentic do |c|
c.validate_login_field = false
c.validate_password_field = false
c.require_password_confirmation = true
c.logged_in_timeout(15.minutes)
end
validates :name, :presence => {:message => 'cannot be blank.'}, :allow_blank => true, :length => {:minimum => 3, :maximum => 40}, :on => :create
validates :email, :presence => {:message => 'address cannot be blank.'}, :allow_blank => true, :format => {:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/, :message => 'address is not valid. Please, fix it.'}, :uniqueness => true
validates :password, :presence => {:message => 'cannot be blank.'}, :allow_blank => true, :length => { :minimum => 6, :maximum => 40}, :on => :create
validates :password_confirmation, :presence => {:message => 'cannot be blank.'}, :allow_blank => true, :length => { :minimum => 6, :maximum => 40 }, :on => :update
end
and my method that saving new password:
def change_password
#user = current_user
if #user.valid_password?(params[:user][:old_password])
if #user.update_attributes(params[:user].reject{|key, value| key == "old_password"})
flash[:notice] = 'Your password was successfuly changed.'
redirect_to :back
else
flash[:warning] = 'You did not fill twice your new password correctly. Please, fix it.'
redirect_to :back
end
else
flash[:warning] = 'Your old password is WRONG! What is your malfunction!?!'
redirect_to :back
end
end
My problem is, that if I set the form the old password, then new password (eg. new_password) and then the confirmations of the new password (eg. new_password1), so the new password is changed & saved into the database - but it shouldn't, because the new password and the confirmation of the new password aren't the same...
How I should set up the validation rules or, where could be a problem?
Thanks for advices
You need to validate the password only if it's being changed. If it's not being changed, then the validation for the password field should be skipped.
Railscasts.com episode #41 shows you how to do this.

failed to test create action

I am playing with rails 3.0.6 with ruby 1.9.2,
the app is working on browser but not in testing..
1) I created a new rails application by "rails new myapp"
2) Generate a scaffold "rails generate scaffold user username:string hashed_password:string salt:string"
3) after that, i changed the users_controller a bit
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully created.") }
format.xml { render :xml => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
// change #user to usrs_url
format.html { redirect_to(users_url, :notice => "User #{#user.username} was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
4) so i try to modify tests as well:
setup do
#input_attributes = {
:username => 'username#goodmail.com',
:password => 'secret',
:password_confirmation => 'secret'
}
#user = users(:one)
end
test "should create user" do
assert_difference('User.count') do
post :create, :user => #input_attributes
end
assert_redirected_to users_path
end
test "should update user" do
put :update, :id => #user.to_param, :user => #input_attributes
assert_redirected_to users_path
end
But the create and update tests failed
Can anyone let me know what had i done wrong?
Thanks
Loaded suite C:/Ruby192/lib/ruby/1.9.1/rake/rake_test_loader
Started
F.....F
Finished in 5.628874 seconds.
1) Failure:
test_should_create_user(UsersControllerTest) [test/functional/users_controller_test.rb:26]:
"User.count" didn't change by 1.
<3> expected but was
<2>.
2) Failure:
test_should_update_user(UsersControllerTest) [test/functional/users_controller_test.rb:45]:
Expected block to return true value.
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
require 'digest/sha2'
class User < ActiveRecord::Base
validates :username, :presence => true, :uniqueness => true
validates_format_of :username, :with => /\A^[^\r\n# ][^\r\n# ]+#[^\r\n# ]+[.][^\r\n#. ]+$\Z/i
#password is a fake field
validates :password, :confirmation => true
validate :password_must_be_present
attr_accessor :password_confirmation
attr_reader :password
def password=(password)
if password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password, salt)
end
end
class << self
def encrypt_password(password, salt)
Digest::SHA2.hexdigest(password + "shrimpy" + salt)
end
def authenticate(username, password)
if user = find_by_username(username)
if user.hashed_password == encrypt_password(password, user.salt)
user
end
end
end
end
private
def password_must_be_present
errors.add(:password, "Missing password") unless hashed_password.present?
end
def generate_salt
self.salt = self.object_id.to_s + rand.to_s
end
end
assert_redirected_to user_path is singular. You probably don't even have a singular user resource route defined. What you want there is probably assert_redirected_to users_path with a plural users.