Rails trouble writing integration test for uploading array of files - ruby-on-rails-4

I'm having trouble getting an integration test to pass. A user creates a product, which can have many pictures. The product's new.html.erb contains file field <%= file_field_tag "images[]", type: :file, multiple: true %> The code works fine, I'm just having problems creating a working integration test.
products_creation_test.rb:
require 'test_helper'
class ProductsCreationTest < ActionDispatch::IntegrationTest
.
.
.
test "should create new product with valid info" do
log_in_as(#user)
pic1 = fixture_file_upload('test/fixtures/cat1.jpg', 'image/jpg')
pic2 = fixture_file_upload('test/fixtures/profile.png', 'image/png')
assert_difference 'Product.count', 1 do
post user_products_path(#user), product: { title: 'test',
description: 'test',
price: '5.99',
images: [pic1, pic2] }
end
assert_redirected_to #user
#user.reload
newprod = #user.products.last
pics = newprod.pictures.all
assert_equal 2, pics.count
end
end
This fails the last assertion, stating that there are no pictures associated with the new product, when there should be 2. inspecting the pics variable, i get the following error: RuntimeError: #<ActiveRecord::AssociationRelation []
What am I missing?
my model structure is as follows:
User has_many Products, Products has_many Pictures
products_controller.rb:
class ProductsController < ApplicationController
before_action :valid_user, only: [:new, :create, :edit, :update]
.
.
.
def create
#product = current_user.products.build(product_params)
if #product.save
# to handle multiple images upload on create
if params[:images]
params[:images].each { |image|
#product.pictures.create(image: image)
}
end
flash[:success] = "Product Created!"
redirect_to current_user
else
flash[:alert] = "Something went wrong."
render :new
end
end
.
.
.
end
pictures_controller.rb:
class PicturesController < ApplicationController
def create
#picture = Picture.new(picture_params)
#picture.save
end
def destroy
end
private
def picture_params
params.require(:picture).permit(:product_id, :image, :_destroy)
end
end
picture.rb:
class Picture < ActiveRecord::Base
belongs_to :product
mount_uploader :image, PicturesUploader
validates_integrity_of :image
validates_processing_of :image
validates :image, file_size: { less_than: 10.megabytes }
end

Solved as follows:
revised products_creation_test.rb:
require 'test_helper'
class ProductsCreationTest < ActionDispatch::IntegrationTest
.
.
.
test "should create new product with valid info" do
log_in_as(#user)
pic1 = fixture_file_upload('test/fixtures/cat1.jpg', 'image/jpg')
pic2 = fixture_file_upload('test/fixtures/profile.png', 'image/png')
assert_difference 'Product.count', 1 do
post user_products_path(#user), product: { title: 'test',
description: 'test',
price: '5.99',
}, images: [pic1, pic2]
end
assert_redirected_to #user
newprod = assigns(:product)
assert_equal 2, newprod.pictures.count
end
end

Related

rails 4 semantic ui multi-select show user selections on edit

I am trying to implement multi-select in a form in rails 4, using Semantic UI. I want users to be able to select multiple categories for each post. So far, I am able to display the dropdown select field which pulls all the categories from the database as follows:
<%= form_for #post, :html => {:class => "ui form bk-form group"} do |f| %>
<label>Post title:</label><br />
<%= f.text_field :title, autofocus: true %>
<label>Choose a category:</label><br />
<%= f.select(:category_ids,options_for_select(Category.all.collect{|x| [x.name,x.id,class:'item']}),{prompt:'Select categories'}, multiple: true, class:'ui fluid dropdown selection multiple')%>
<% end %>
With this, I am able to create and save posts and the data is inserted in the database. However, when I try to edit an article, the pre-selected categories do not show. I have tried to set the value: #post.categories option in the select field and still cannot get the existing categories to show. Thanks in advance for your thoughts.
UPDATED
Models are as follows:
class Post < ActiveRecord::Base
has_many :post_categories
has_many :categories, through: :post_categories
end
class Category < ActiveRecord::Base
has_many :post_categories
has_many :posts, through: :post_categories
end
class PostCategory < ActiveRecord::Base
belongs_to :post
belongs_to :category, :counter_cache => :posts_count
end
Then my posts_controller.rb
class PostsController < ApplicationController
before_action :set_post, only: [:edit, :update, :show]
def index
#posts = Post.all
end
def new
end
def create
#post = Post.new(post_params)
#post.user = current_user
if #post.save
flash[:notice] = "Post was successfully created"
redirect_to user_posts_path
else
flash[:alert] = "Oh Snap!! We could not save your post"
render 'new'
end
end
def edit
end
def update
if #post.update(post_params)
flash[:notice] = "Post was successfully updated"
redirect_to user_posts_path
else
flash[:alert] = "Oh Snap!! We could not update your post"
render 'edit'
end
end
private
def post_params
params.require(:post).permit(:title, :description, :published, :tag_list, category_ids: [])
end
def set_post
#post = Post.find(params[:id])
end
end

Rails - Adding a "Delete" button to a Users Timetable

Hi I have a rails App where Users can have a timetable with a one to many relationship.
When i add this
<%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
to _user.html it renders a delete link which deletes a user no problem
but when i add this
<%= link_to "delete", timetable, method: :delete,
data: { confirm: "You sure?" } %>
to _timetable.html.erb it throws an error
ActionController::RoutingError (No route matches [DELETE] "/timetable.4"):
My Routes.rb
get 'password_resets/new'
get 'password_resets/edit'
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'timetable' => 'timetables#new'
get 'signup' => 'users#new'
get 'mobile' => 'users#mobile'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :timetables
resources :users
resources :projects
Timetable Controller
class TimetablesController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def index
#timetables = current_user.timetables.find(current_user)
end
def new
#user = User.find(current_user)
#timetable = Timetable.new
#timetables = #user.timetables.paginate(page: params[:page], per_page: 1)
end
def feed
Timetable.where("user_id = ?", id)
end
def show
#feed_items3 = current_user.feed.paginate(page: params[:page])
#timetable = current_user.timetables.find(params[:id])
end
def create
#timetable = Timetable.new(timetable_params)
#user = User.find(current_user)
if current_user.timetables.create(timetable_params)
flash[:success] = "Timetable created!"
redirect_to timetable_path
else
flash[:success] = "Timetable not created!"
redirect_to timetable_path
end
end
def destroy
#timetable = Timetable.find(params[:id])
#timetable.destroy
redirect_to timetables_path, notice: "The timetable #{#timetable.name} has been deleted."
end
private
def timetable_params
params.require(:timetable).permit(:name, :attachment, :id)
end
def correct_user
#project = current_user.projects.find_by(id: params[:id])
redirect_to root_url if #project.nil?
end
end
Without seeing your Controllers it is hard to be sure, but I would look at a few areas:
Specifying the path & the timetable object to be deleted:
<%= link_to "Delete Timetable", timetable_path(timetable), :method => :delete %>
Ensure that the destroy action for the timetable sits within the timetable_controller
Regarding your routes.rb file I am not sure why you need:
get 'timetable' => 'timetables#new'
and then also
resources :timetables
This is duplication - why not try use 'only' (edit to your preference):
resources :timetables, only: [:index, :new, :create, :destroy]

How to make comment field in post in ruby on rails app

I want to add comment in post in simply ruby on rails application.
Resolved.
My Controller:
class CommentsController < ApplicationController
before_filter :authenticate_user!
def create
binding.pry
#adventure = Adventure.find(params[:adventure_id])
#comment = #adventure.comments.create(comment_params)
if #comment.save
flash[:notice] = "Comment has been created."
redirect_to #adventure
else
flash.now[:danger] = "error"
end
end
def comment_params
params.require(:comment).permit(:body)
end
end
class Comment < ActiveRecord::Base
belongs_to :adventure
end

Rails 4 + ActiveAdmin passing params to another model and creating an object (with relations)

Total Rails novice here, just coming from PHP.
I'm running a Rails4+Active Admin setup with (device/cancan (disregarding those now).
Implementing strong_parameters. Please note, the code is totally broken. I've tried it in a bunch of ways and this is as close as I've gotten. Hopefully it gives a view into what I'm trying to do.
Been following a tutorial on implementing an API key setup, and trying to modify it to be able to generate an APIKey for a user in the admin.
I've added a column to AdminUser to generate an APIKey
It is correctly linked to
#app/admin/admin_users.rb
ActiveAdmin.register AdminUser do
index do
column :email
column :current_sign_in_at
column :last_sign_in_at
column :sign_in_count
default_actions
column('API', :sortable => :id) { |resource| link_to "(Re)Generate Key", new_admin_admin_user_api_key_path(resource.id) }
end
end
Which gives me a (correct) link to
/admin/admin_users/:admin_user_id/api_keys/new(.:format)
# app/admin/api_key.rb
ActiveAdmin.register APIKey do
belongs_to :admin_user
controller do
def create_for admin_user
key = APIKey.new
key.assign_params_from_controller(admin_user)
APIKey.create(:admin_user_id => params[:admin_user_id]);
end
def permitted_params
params.permit create_for [:admin_user_id]
end
end
end
#app/models/api_key.rb
class APIKey < ActiveRecord::Base
before_create :generate_access_token
belongs_to :admin_user, :foreign_key => "id", :inverse_of => :api_key
attr_accessible :admin_user_id
def assign_params_from_controller(params)
#params = params
end
private
def generate_access_token
begin
self.admin_user_id = params.admin_user_id
self.access_token = SecureRandom.hex
end while self.class.exists?(admin_user_id: admin_user_id, acces_token: access_token)
end
end
This code gives me:
NameError in Admin::APIKeysController#new
undefined local variable or method `params' for #<APIKey:0x000000078d6470>
def generate_access_token
begin
self.admin_user_id = params.admin_user_id
self.access_token = SecureRandom.hex
end while self.class.exists?(admin_user_id: admin_user_id, acces_token: access_token)
end
UPDATE, ANSWER:
Problem solved.
Ended up being on the right track. But was straying off because of type conversion errors.
My admin_user_id ended up being a 'string' in the database. Nice copy-paste job there.
Wrote a migration first
class AlterTableAPIKeys < ActiveRecord::Migration
def up
execute "DELETE FROM `api_keys` WHERE 1"
change_column :api_keys, :access_token, :string, { null: false }
change_column :api_keys, :admin_user_id, :integer, { null: false }
add_column :api_keys, :active, :boolean, {null: false, default: true }
remove_column :api_keys, :role
add_index :api_keys, ["admin_user_id"], name: "index_api_keys_on_admin_user_id", unique: false
add_index :api_keys, ["access_token"], name: "index_api_keys_on_access_token", unique: true
end
end
I didn't pass the access_token to the create.
I ended up with this.
# app/admin/api_key.rb
ActiveAdmin.register APIKey do
belongs_to :admin_user
controller do
def new
key = APIKey.create(:admin_user_id => params[:admin_user_id])
{:access_token => key.access_token}
redirect_to admin_admin_users_path, :notice => "API Key #{key.access_token} created! "
end
def permitted_params
params.permit api_key: [:admin_user_id]
end
end
end
# app/models/api_key.rb
class APIKey < ActiveRecord::Base
attr_accessible :access_token, :expires_at, :admin_user_id, :active, :application
before_create :generate_access_token
before_create :set_expiration
belongs_to :admin_user
def expired?
DateTime.now >= self.expires_at
end
private
def generate_access_token
begin
self.access_token = SecureRandom.hex
end while self.class.exists?(access_token: access_token)
end
def set_expiration
self.expires_at = DateTime.now+30
end
end
Obviously this does not account for access, might solve that with roles (i.e. uberadmin can regenerate other admins API, admins only their own).

Carrierwave only upload image when update action when using Rails 4 and nested form

My model:
class Product < ActiveRecord::Base
has_many :product_images, dependent: :destroy
accepts_nested_attributes_for :product_images, :reject_if => lambda { |p| p['image'].blank? }, :allow_destroy => true
end
class ProductImage < ActiveRecord::Base
belongs_to :product
mount_uploader :image, ProductImageUploader
validates_presence_of :image
end
My controller:
def create
#product = Product.new(permitted_params.product)
if #product.save
redirect_to edit_admin_product_path(#product), notice: "success"
else
render :new
end
end
def update
#product = Product.find(params[:id])
if #product.update_attributes(permitted_params.product)
redirect_to edit_admin_product_path(#product), notice: "success"
else
render :edit
end
end
permitted_params:
class PermittedParams < Struct.new(:params)
def product
params.require(:product).permit(*product_attrs)
end
def product_attrs
[:name, :content, :stock, :list_price, :selling_price, :bonus, :is_added,
product_images_attributes: [:id, :image, :_destroy] ]
end
end
And parameters passed:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eqweq1231sda+3T0131643guXybT75X6NqN1ng=", "product"=>{"name"=>"weqwe", "content"=>"qweq", "product_images_attributes"=>{"0"=>{"image"=>"1069218_513152615405563_1187314087_n.jpg", "_destroy"=>""}}, "stock"=>"", "list_price"=>"", "selling_price"=>"123", "bonus"=>""}, "commit"=>"submit"}
Obviously the image is pass to the params. but when create product it will rollback to alarm the image is empty(validate presence image in my ProductImage model).
If I delete the validation then create the product. I can successfully upload the images in update action. I have totally no idea what's the problem! Please help. Q_Q