How to test the removal of images using Ajax in Rspec - ajax

I have an images on the page, which I removed via Ajax.
I want to test deleting images.
Controller:
def destroy
current_image = Image.find(params[:id])
current_car = current_image.car
Image.delete_image_file(params[:id])
flash[:notice] = t('activerecord.errors.controllers.message.attributes.image.image_destroy_success')
#images = current_car.images.order("order_id")
respond_to do |format|
format.html { redirect_to images_path(:car_id => params[:id]) }
format.js
end
end
File destroy.js.erb - Refreshing view and showing flash message
$('#image_list').html("<%= escape_javascript(render('list')) %>")
$('#div_flash_box').html("<%= escape_javascript(render :partial => 'layouts/flash', :locals => { :flash => flash }).html_safe %>")
View of images: _list.html.erb
<ul id="ul_images" data-update-url="<%= sort_images_url %>">
<% #images.each do |image| %>
<%= content_tag_for :li, image, :class => 'ui-state-default' do %>
<%= link_to image_tag("#{RAILS_CAR_VIEW_IMAGES}" + "#{image.name}/" + image.image_thumb_file), "#{RAILS_CAR_VIEW_IMAGES}" + "#{image.name}/" + image.image_file, :class => 'group1' %>
<div class="div-images-delete"><%= link_to t('views.buttons.delete'), image, :method => :delete, :remote => true, :confirm => t('views.forms.confirm') %></div>
<% end %>
<% end %>
</ul>
My tests in Rspec
it "should delete an image using Ajax" do
lambda do
xhr :delete, :destroy, :id => #image.id
response.should be_success
end.should change(Image, :count).by(-1)
end
it "should destroy image" do
xhr :delete, :destroy, :format => "html"
flash[:notice].should == I18n.t('activerecord.errors.controllers.message.attributes.image.image_destroy_success')
end
Cars and Images are in relationships
class Image < ActiveRecord::Base
belongs_to :car,
:foreign_key => "car_id"
class Car < ActiveRecord::Base
has_many :images
Failures:
1) ImagesController for signed-in users should delete an image using Ajax
Failure/Error: xhr :delete, :destroy, :id => #image.id
NoMethodError:
undefined method images' for nil:NilClass
# ./app/controllers/images_controller.rb:32:indestroy'
# ./spec/controllers/images_controller_spec.rb:36:in block (4 levels) in <top (required)>'
# ./spec/controllers/images_controller_spec.rb:35:inblock (3 levels) in '
2) ImagesController for signed-in users should destroy image
Failure/Error: xhr :delete, :destroy, :format => "html"
ActionController::RoutingError:
No route matches {:format=>"html", :controller=>"images", :action=>"destroy"}
# ./spec/controllers/images_controller_spec.rb:42:in `block (3 levels) in '
What's wrong?

For the first error, I believe that the current_car object has not been set in the test environment. That's why there is a NilClass error when .images is called.

The first error is because the image you're trying to delete doesn't have an associated car. This sounds like you forgot to create a car when creating the data for this test.
The other error is because you missed the id parameter in the test:
xhr :delete, :destroy, :format => "html"
should be
xhr :delete, :destroy, :id => #image.id, :format => "html"

Related

one time payment stripe and rails 4

I've started implemented the system for a one time payment on rails with stripe from the tutorial on stripe.com. however when proceeding it does not take into consideration the discount and amount remain the same.
`enter code here`enrollments_controller.rb that will include the charge
def create
#disable_navbar = true
#disable_footer = true
#lecture = Lecture.find_by(params[:id])
#enrollment = Enrollment.new(enrollment_params)
# Test for stripe
if #enrollment.valid?
begin
#amount = #lecture.amount
#final_amount = #amount
#code = params[:couponCode]
if #code.blank?
#discount = get_discount(#code)
if #discount.nil?
flash[:error] = 'Coupon code is not valid or exprired'
redirect_to new_enrollment_path
return
else
#discount_amount = #amount * #discount
#final_amount = #amount * #discount_amount.to_i
end
charge_metadata = {
:coupon_code => #code,
:coupon_discount => (#discount * 100).to_s + '%'
}
end
charge_metadata ||= {}
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
Stripe::Charge.create(
:customer => customer.id,
:amount => #final_amount,
:description => 'Rails Stripe customer',
:currency => 'usd',
:metadata => charge_metadata
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_enrollment_path
end
#enrollment.save
ConfirmationEnrollmentMailer.confirmation_enrollment(current_user, #lecture, #enrollment).deliver
redirect_to profile_path(current_user)
flash[:success] = "You have successfully enrolled."
else
flash[:error] = 'You have already registered for this class'
redirect_to profile_path(curren)
end
end
private
def enrollment_params
params.require(:enrollment).permit(:user_id, :lecture_id, :amount)
COUPONS = {
'TEST' => 0.10
}
def get_discount(code)
code = code.gsub(/ +/, '')
code = code.upcase
COUPONS[code]
end
And here is the form in enrollments/new
<%= form_for #enrollment do |f| %>
<% if flash[:error].present? %>
<div class="error_explanation">
<p><%= flash[:error] %></p>
</div>
<% end %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :lecture_id, value: #lecture.id %>
<%= label_tag(:couponCode, 'Enter Coupon') %>
<%= text_field_tag(:couponCode) %>
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="PUBLISHABLE KEY (is set in secret.yml)"
data-description="Your purchase"
data-locale="auto">
</script>
<% end %>
Rails not raising error but not applying the discount.

Include ajax comments in index in rails 4

I have ajax comments in my rails app and it all works in the posts show but I'd like to add the form to render the comments in the index page.
I'm using sorl when rendering the index page and I tried to include comments in the post model like this:
searchable(:include => :comments) do
code....
end
but that doesn't render the comments below the posts in the index page, even though I have this in the view
<%= render :partial => 'comments/comment',:collection => #comments, :as => :comment %>
So to help you understand, here is all the code:
_post.html.erb:
<%= simple_form_for [post, Comment.new], :url => comments_path, :remote => true do |f| %>
<%= image_tag current_user.avatar.url(:small) %>
<%= f.input :body, placeholder: 'write a comment...', :input_html => { :rows => "1"}, :label => false %>
//the below two lines do not work, the commentable_id is 0 and commentable_type is blank
//post.comments.commentable_id doesn't work either
<%= f.input :commentable_id, :as => :hidden, :value => Comment.new.commentable_id %>
<%= f.input :commentable_type, :as => :hidden, :value => Comment.new.commentable_type %>
<%= button_tag(type: 'submit', :id => 'commentsend') do %>
<i class="fa fa-check"></i>
<% end %>
<% end %>
<%= render :partial => 'comments/comment',:collection => #comments, :as => :comment %>
Posts_controller:
def index
#user_count = User.where(:school => current_user.school).count
#blub_count = Post.where(:category => "status").where(:school => current_user.school).count
#items_count = Post.where(:school => current_user.school).where.not( :category => "status").count
#search = Post.search(:include => :comments) do #Post.search do
fulltext params[:search]
with(:school, current_user.school)
paginate :page => params[:page], :per_page => 20
order_by(:updated_at, :desc)
end
#posts = #search.results
respond_to do |format|
format.js
format.html
end
end
def show
#post = Post.find(params[:id])
#comments = #post.comment_threads.order('created_at desc')
#new_comment = Comment.build_from(#post, current_user, "")
end
comments_controller:
def create
#comment_hash = params[:comment]
#obj = #comment_hash[:commentable_type].constantize.find(#comment_hash[:commentable_id])
# Not implemented: check to see whether the user has permission to create a comment on this object
#comment = Comment.build_from(#obj, current_user.id, #comment_hash[:body])
if #comment.save
render :partial => "comments/comment", :locals => { :comment => #comment }, :layout => false, :status => :created
else
render :js => "alert('error saving comment');"
end
end
comments model:
acts_as_nested_set :scope => [:commentable_id, :commentable_type]
validates :body, :presence => true
#validates :user, :presence => true
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_votable
belongs_to :commentable, :polymorphic => true
# NOTE: Comments belong to a user
belongs_to :user
belongs_to :post
# Helper class method that allows you to build a comment
# by passing a commentable object, a user_id, and comment text
# example in readme
def self.build_from(obj, user_id, comment)
new \
:commentable => obj,
:body => comment,
:user_id => user_id
end
#helper method to check if a comment has children
def has_children?
self.children.any?
end
# Helper class method to lookup all comments assigned
# to all commentable types for a given user.
scope :find_comments_by_user, lambda { |user|
where(:user_id => user.id).order('created_at DESC')
}
# Helper class method to look up all comments for
# commentable class name and commentable id.
scope :find_comments_for_commentable, lambda { |commentable_str, commentable_id|
where(:commentable_type => commentable_str.to_s, :commentable_id => commentable_id).order('created_at DESC')
}
# Helper class method to look up a commentable object
# given the commentable class name and id
def self.find_commentable(commentable_str, commentable_id)
commentable_str.constantize.find(commentable_id)
end
The comments form shoudl be like this:
<%= simple_form_for Comment.build_from(post, current_user, ""), :url => comments_path, :remote => true do |f| %>
I have to assign the comment the current post ID(commentable_id) and current user id for commentable_type to build the comment
in the view, to render the comments I used
<%= render post.comment_threads.order('created_at desc') %>
the only issue is the the render is ignoring the div

Rails form validation works in one template but not another for the same Model

Another hair-puller. AFter two days of fighting with this I cannot figure out what is wrong here.
Basically I have a form validation triggered by the model:
validates :user, :presence => true, :uniqueness => true
validates :email, :presence => true, :uniqueness => true, :on => :create
validates :passwordHash, :presence => true, :confirmation => true, :on => :create
The user not being empty works on the update form View:
= simple_form_for #user do |f|
= f.input :user
= f.input :locale
= f.input :localeLanguage, :label => 'Language', :as => :select, :collection => $language_array
= f.input :moderator
= f.input :email
= f.input :passwordHash, :label => 'Password'
But not on the new users View:
= simple_form_for #user do |f|
%table.table-condensed
%tr
%td
=f.input :user, :label => false, :placeholder => 'username'
%tr
%td
= f.input :passwordHash, :label => false, :placeholder => 'password'
%tr
%td
= f.input :email, :label => false, :placeholder => 'email'
%tr
%td
= f.submit "Create User", :class => 'btn btn-primary'
The only difference I can see between these views is that the first one has sessions created since a user has already logged in, the second one doesn't. But as far as I know this should not make a difference. Of course, the update form does have an actual #user object whereas in the new one it is empty. But I've seen Ryan Bates' railscast of a new user validation and he does pretty much the same thing.
What happens is the users#create action being invoked after submitting the form with empty values (which should not be possible). Of course I get an error because the passwordHash is empty.
I should point out that I'm not using any extra gems to aid in password confirmation (in the railscast, Bates uses bcrypt but I can't use it because we create the password hash a different way plus I think that's for the password confirmation magic only). In any case this should not affect the form validation should it?
Any theories or ideas are welcome here, I'm going crazy. I'm about to write some crappy javascript to do it by hand which would be awful and would probably take me a week, I don't do javascript ;)
Thanks.
Edit
Per Rachid's request, here are the new and create actions:
def new
#user = User.new
end
def create
#failsafe for failing form validation
unless params[:passwordHash].present?
redirect_to new_user_path, :notice => 'User or password cannot be blank'
else
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt)
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
redirect_to new_user_path, :notice => "User already exists, please pick another one"
end
end
end
Edit 2
I've rewritten the create method based on the first answer, but still getting an error:
def create
respond_to do |format|
if params[:passwordHash].present? && params[:user].present?
password_and_salt = User.hash_password(params[:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
#user = User.new(:user => params[:user], :passwordHash => hashed_password, :salt => user_salt, :online_user => 1 )
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
The error is undefined method 'model_name' for NilClass:Class for this line:
= simple_form_for #user do |f|
Obviously the #user = User.new is not making it back to the form. At this point I'm a little confused as to how I should write the create method for it to work properly and show the error messages. But I feel I'm closer :)
#misha, here is the update controller action, it's just pretty standard scaffolding:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
if session[:return_to]
format.html { redirect_to session[:return_to], :notice => 'User was successfully updated.' }
else
format.html { redirect_to users_path, :notice => 'User was successfully updated.' }
end
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
First of all what you assume here is incorrect:
What happens is the users#create action being invoked after submitting
the form with empty values (which should not be possible). Of course I
get an error because the passwordHash is empty.
It is possible that users#create is invoked and actually it should happen. It is in the create action where you handle this stuff. I think your problem is the fact that you do a redirect if the #user is not saved. You should render the view again, so the error messages can be displayed.
So instead of:
redirect_to new_user_path, :notice => "User already exists, please pick another one"
Try:
render :action => 'new'
Edit based on your comment:
When validation fails Rails populates #user.errors automatically. You don't have to do anything in the controller (i.e. your create action)! All you have to do is display the errors in #user.errors in your view.
About the error you are getting now:
The reason you are getting the error is that #user is not set. You have to rewrite your create method to something like this:
def create
respond_to do |format|
if params[:user][:passwordHash].present?
password_and_salt = User.hash_password(params[:user][:passwordHash])
hashed_password = password_and_salt[:password]
user_salt = password_and_salt[:salt]
end
#user = User.new(params[:user].merge({:passwordHash => hashed_password, :salt => user_salt, :online_user => 1}))
if #user.save
session[:user_id] = #user.id
redirect_to session[:item_to_edit]
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end

best_in_place gem to edit currency

I'm using the best_in_place gem to edit balances:
index.html.erb:
<%= best_in_place bankaccount, :balance, :display_with => :number_to_currency %>
but after editing, I get a unformatted number ($45 changed to 46 shows as 46).
How do I get best_in_place to display the new value as $$$?
controller:
respond_to :html, :json
...
def update
#bankaccount = Bankaccount.find(params[:id])
if #bankaccount.update_attributes(params[:bankaccount])
respond_with #bankaccount
else
render :json => #bankaccount.errors.full_messages, :status => :unprocessable_entity
end
# if #bankaccount.update_attributes(params[:bankaccount])
# redirect_to #bankaccount, :notice => "Successfully updated bankaccount."
# else
# render :action => 'edit'
# end
end
This thread is already answered but I tried the accepted answer and it didn't work.
However using a lambda everything is nice again. Rails 4, by the way.
<%= best_in_place #text, :body, :type => :textarea, :display_with => lambda{ |v| markdown(v) }, :html_attrs => { :class => 'edit-text-body' } %>
Ended up using BIP's :display_as => :mk_bal with mk_bal defined in model Bankaccount as:
def mk_bal
ActionController::Base.helpers.number_to_currency(self.balance, :precision => 2)
end

Undefined method 'title' for nil:NilClass

I am following railsspace book but when i trying edit show and eliminate a post owner (chapter 15) I get: error message
undefined method `title' for nil:NilClass
follow extact:
1: <div class="post">
2: <div class="post_title">
3:
4: <%= sanitize post.title %>
5: <% unless hide_edit_links? %>
6: <span style="float:right">
7: <%= link_to_unless_current 'Mostrar', blog_post_path(post.blog, post) %> |
Ruby 1.9.2
Rails 3.1.3
The controller, views and routes is as follow:
Controller: posts_controller
# Encoding: UTF-8
class PostsController < ApplicationController
helper :profile
before_filter :protect, :protect_blog
# GET /posts
# GET /posts.xml
def index
#Recheck implement paginate for Rails 3.1.3
##pages, #posts = paginate(#blog.posts)
#posts = #blog.posts
#title = "Administración del Blog"
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => #posts.to_xml }
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
#title = #post.title
respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => #post.to_xml }
end
end
# GET /posts/new
def new
#post = Post.new
#title = "Nuevo post"
end
# GET /posts/1;edit
def edit
#post = Post.find(params[:id])
#title = "Edit #{#post.title}"
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
#post.blog = #blog
respond_to do |format|
if #post.duplicate? or #blog.posts << #post
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to blog_post_url(:id => #post) }
format.xml { head :created, :location => blog_post_url(:id => #post) }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors.to_xml }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to post_url(:id => #post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors.to_xml }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.xml { head :ok }
end
end
private
# Ensure that user is blog owner, and create #blog.
def protect_blog
#blog = Blog.find(params[:blog_id])
user = User.find(session[:user_id])
unless #blog.user == user
flash[:notice] = "That isn't your blog!"
redirect_to hub_url
return false
end
end
end
View: index
<h2>Sus Blog Posts</h2>
<p class="edit_link">
<%= link_to 'Agregar nuevo post', new_blog_post_path %>
<%= "| Pages: #{pagination_links(#pages)}" if paginated? %>
</p>
<%= render :partial => "post", :collection => #posts %>
View: post
<div class="post">
<div class="post_title">
<%= sanitize post.title %>
<% unless hide_edit_links? %>
<span style="float:right">
<%= link_to_unless_current 'Mostrar', blog_post_path(post.blog, post) %> |
<%= link_to_unless_current 'Editar', edit_blog_post_path(post.blog, post) %> |
<%= link_to 'Eliminar', blog_post_path(post.blog, post),
:confirm => 'Deseas eliminar este post?', :method => :delete %>
</span>
<% end %>
</div>
<div class="post_body"><%= sanitize post.body %></div>
<div class="post_creation_date">
Publicado <%= time_ago_in_words post.created_at %> ago
<% if post.updated_at != post.created_at %>
<br /> Modified <%= time_ago_in_words post.updated_at %> ago
<% end %>
</div>
</div>
In this view , i has triying put # in the variable post =#post, but it not work
Routes
Expression::Application.routes.draw do
get "email/remind"
get "avatar/index"
get "avatar/upload"
get "avatar/delete"
get "community/index"
get "community/browse"
get "community/search"
get "faq/index"
get "faq/edit"
get "spec/index"
get "spec/edit"
get "profile/index"
get "profile/show"
get "user/index"
get "user/register"
get "site/index"
get "site/about"
get "site/help"
get "user/login"
get "user/logout"
get "user/edit"
get "user_mailer/welcome_email"
post "user/register"
post "user/login"
post "user/edit"
post "spec/edit"
post "faq/edit"
post "community/index"
post "community/search"
post "avatar/upload"
post "email/remind"
resources :blogs do
resources :posts
end
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => 'welcome#index'
root :to => 'site#index'
# match'', :controller => 'site', :action => 'index', :id => nil
resources :user
match '/register', :to => 'user#register'
match '/about', :to => 'user#about'
match '/help', :to => 'user#help'
match '/login', :to =>'user#login'
match '/edit', :to =>'user#edit'
match '/user/welcome_email', :to => 'user#create'
#resources :profile
#match '/show', :to => 'profile#show'
# Install the default route as the lowest priority.
match ':controller/:action/:id'
match 'profile', :to => 'profile#show', :as => "profile"
match 'hub', :to => 'user#index', :as => 'hub'
##Change Route pagina 343
# You can have the root of your site routed by hooking up ''
# -- just remember to delete public/index.html.
match '', :controller => 'site', :action => 'index', :id => nil
###
#match'', :controller => 'user', :action => 'about', :id => nil
#match'', :controller => 'user', :action => 'help', :id => nil
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id(.:format)))'
end
ApplicationStacktrace
app/views/posts/_post.erb:4:in `_app_views_posts__post_erb__1793130860277527745_40556500'
app/views/posts/show.html.erb:3:in `_app_views_posts_show_html_erb__2356198700875868089_40643800'
app/controllers/posts_controller.rb:23:in `show
Use #post.title, instead of post.title on line 4 of your template.
After deleting your code is trying to redirect to posts_url.
However I do not see that in your routes. btw you can also do rake routes at the command line to see what your routes are.
I think you need to add a get for posts/index although I would really look to try and use RESTful routing which would clean up much of your routes.

Resources