How to implement upload photo feature in rails? - ruby-on-rails

My repo: https://github.com/Gtar69/artstore_hw2
I want to implement upload more than 1 photo in certain product.
The basic idea is that administrator enter edit page of the product and can "upload new photos" for certain product.Im struggling in "how to create a photo object in edit page and add this photo object to product. !!! I can not successfully create a photo object in edit page .....
Very Thanks
in view/admin/products/edit.html.erb
<h2> 編輯 <%= #product.title %> </h2>
<%= simple_form_for [:admin, #product ] , :html => { :class => "form form-horizontal" } do |f| %>
<div class="form-group">
<div class="col-sm-10">
<%= f.input :title %>
</div>
</div>
<div class="form-group">
<div class="col-sm-10">
<%= f.input :description, :as => :text %>
</div>
</div>
<div class="form-group">
<div class="col-sm-1">
<%= f.input :quantity %>
</div>
</div>
<div class="form-group">
<div class="col-sm-1">
<%= f.input :price %>
</div>
</div>
<!-- 20140623 upload more than one photo feature added -->
<div>
<%= simple_form_for [:admin, #product, #product.photos.build] do |f| %>
<%= f.input :image , :as => :file %>
<div class="form-group">
<%= f.submit "upload new photos", :class => "btn btn-default" , :disable_with => 'Submiting...' %>
</div>
<%end%>
</div>
<div class="form-group">
<%= f.submit "Submit", :class => "btn btn-default" , :disable_with => 'Submiting...' %>
</div>
<% end %>
in controllers/admin/products_controller.rb
def edit
#product = Product.find(params[:id])
##photo = #product.photos.build
##product.add_photo_to_product(#photo)
end
in controllers/admin/photos_controller.rb
def create
#binding.pry
#product = Product.find(params[:product_id])
#photo = #product.photos.create(photo_params)
#product.add_photo_to_product(#photo)
redirect_to admin_products_path
end
private
def photo_params
params.require(:photo).permit(:image)
end
in model/product.rb
class Product < ActiveRecord::Base
has_many :photos
accepts_nested_attributes_for :photos
validates :title , :presence => true
validates :quantity , :presence => true
def default_photo
photos.first
end
def add_photo_to_product(photo)
photos << photo
end
end
in photos.rb
class Photo < ActiveRecord::Base
belongs_to :product
mount_uploader :image, ImageUploader
end

Related

I can't save record in sqlite Rails

I try save record on database, in pivot table but I have a error(screen) if I write #video.category_ids = 1 it works but category id = 1 in database
Below I put my code if you neeed more information please write.
videos_controller.rb
class VideosController < ApplicationController
layout 'master'
before_action :chceck_login
def index
#videos = Video.sortASC
end
def new
#categories = Category.all
end
def create
#video = Video.new(video_params)
#video.category_ids = [video_params]
if #video.save
flash[:notice] = 'The movie has been added successfuly'
redirect_to(:action => 'index')
else
#categories = Category.all
render('new')
end
end
def show
end
def edit
end
def delete
end
private
def video_params
params.require(:video).permit(:title, :url, :description, category_attributes: [:id]).merge(user_id: session[:user_id])
end
end
_form_html.erb
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"><i class="fas fa-tag"></i></span>
</div>
<%= f.text_field :title, placeholder: 'Title', :class => 'form-control', :id => 'title' %>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"><i class="fas fa-link"></i></span>
</div>
<%= f.text_field :url, placeholder: 'URL', :class => 'form-control', :id => 'url' %>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"><i class="fas fa-edit"></i></span>
</div>
<%= f.text_area :description, placeholder: 'Description', rows: 5, :class => 'form-control', :id => 'description' %>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1"><i class="fas fa-sitemap"></i></span>
</div>
<%= f.select(:category_id, #categories.map{|t| [t.name, t.id]}, {}, :multiple => true, :class => 'custom-select') %>
</div>
video.rb
class Video < ApplicationRecord
belongs_to :user
has_and_belongs_to_many :categories
scope :sortASC, lambda{order("videos.created_at ASC")}
end
new.html.erb
<% #page_title = 'Add Film' %>
<div class='container'>
<div class='row'>
<div class='col s-6'>
<div class="jumbotron jumbotron-fluid bg-info">
<div class="container">
<h1 class="display-4 text-center">ADD NEW FILM <i class="fas fa-plus"></i></h1>
<p class="lead">This is a modified jumbotron that occupies the entire horizontal space of its parent.</p>
</div>
</div>
</div>
<div class='col s-6'>
<%= form_for(:video, :url => {:action => 'create'}) do |f| %>
<%= render(:partial => 'form', :locals => {:f => f}) %>
<%= submit_tag('Add Film', :class => 'btn btn-primary float-right') %>
<% end %>
</div>
</div>
</div>
Error
https://imgur.com/7P4WpMU
If you want I have put my project on Github.
I would suggest the following changes:
In _form.html.erb pluralize the name of the select, i.e. change
<%= f.select(:category_id, #categories.map{|t| [t.name, t.id]}, {}, :multiple => true, :class => 'custom-select') %>
to
<%= f.select(:category_ids, #categories.map{|t| [t.name, t.id]}, {}, :multiple => true, :class => 'custom-select') %>
In videos_controller.rb change
def video_params
params.require(:video).permit(:title, :url, :description, category_attributes: [:id]).merge(user_id: session[:user_id])
end
to
def video_params
params[:video][:category_ids].reject!(&:blank?) unless params[:video][:category_ids].nil?
params.require(:video).permit(:title, :url, :description, category_ids: []).merge(user_id: session[:user_id])
end
Also in videos_controller.rb remove
#video.category_ids = [video_params]
to leave things to the constructor
Regarding 2. I am not 100% sure about the exact solution, maybe you should also reject the empty id you have in your parameters (according to the provided screenshot, use .reject!(&:blank?) for that) - for analyzing further problems check the output of the video_params function before passing it to the constructor - it basically should look like a hash representation of the expected object.
edit Updated the change proposal for 2. regarding category_ids

using cocoon and checkboxes , I don't know how to recognize checked: true or false in edit

I am new to develop rails project, I have a nested form for submitting Event and Ticket by using gem 'cocoon'.And the form have some check_boxes .
When you submit new , it does not matter, but in edit, you can not put checked in my checkboxes.
How do i do that given my code below?
My error
undefined method `include?' for nil:NilClass
<%= f.check_box :payment_type, { multiple: true ,checked:f.object.payment_type.include?(pay), include_hidden: false }, pay %>
<%= f.label :payment_type, pay, :value => i %>
My Model
class Event < ActiveRecord::Base
has_many :tickets, inverse_of: :event
accepts_nested_attributes_for :tickets, allow_destroy: true
class Ticket < ActiveRecord::Base
belongs_to :event
My Controller
class EventsController < ApplicationController
before_action :set_event, only: [:show, :edit, :update, :destroy]
def new
#event = Event.new
end
def create
#event = Event.new(event_params)
if #event.save
flash[:notice] = 'wow'
redirect_to #event
else
flash[:notice] = 'oh..'
render 'new'
end
end
def edit
end
def update
if #event.update(event_params)
redirect_to #event
else
render 'edit'
end
end
My form
<div class="nested-fields">
<h3>tickets</h3>
<div class="row formsection text-center">
<div class="col-md-3">
<span class="label-title">fee</span>
</div>
<div class="col-md-9">
<div class='input-group'>
<%= f.text_field :fee, :placeholder => "fee" , :class => "form-control" %>
</div>
</div>
</div>
<div class="row formsection text-center">
<div class="col-md-3">
<span class="label-title">payment</span>
</div>
<div class="col-md-9">
<%= f.hidden_field :id %>
<% payments = { 'paypal' => 1, 'credit card' => 2 } %>
<% payments.each do |pay,i| %>
<%= f.check_box :payment_type, { multiple: true ,checked: f.object.payment_type.include?(i), include_hidden: false }, i %>
<%= f.label :payment_type, pay, :value => i %>
<br>
<% end %>
</div>
</div>
<%= link_to_remove_association 'remove this', f %>
</div>
Not sure why it works on new, but if payment_type is not yet set, and so is nil, this will give the error you showed.
So instead write something like:
<%- checked_value = f.object.payment_type.present? && f.object.payment_type.include?(i) %>
<%= f.check_box :payment_type, { multiple: true ,checked: checked_value, include_hidden: false }, i %>

Rails - Rendering form_for #user in a different view

I'm trying to render this code (partial to update users payment info).
/devise/registrations/_credit.html.erb
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<form action="#">
<div class="form-group">
<label class="control-label">Card Holder Name</label>
<%= f.text_field :name, autofocus: true, class:"form-control" %></div>
<div class="form-group">
<label class="control-label">Card Number</label>
<%= f.text_field :card, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">CVV</label>
<%= f.text_field :cvv, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">Expiration Month</label>
<%= f.text_field :expmonth, autofocus: false, class:"form-control" %>
</div>
<div class="form-group">
<label class="control-label">Expiration Year</label>
<%= f.text_field :expyear, autofocus: false, class:"form-control" %>
</div>
<div class="margin-top-10">
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="actions">
<%= f.submit "Update", class:"btn green" %>
<% end %>
</div>
</form>
</div>
I'm trying to get this partial to show up in a different page that's not under users_controller.rb, but I keep getting an error.
NameError in Orders#new
Showing /home/nitrous/code/uvesty/app/views/devise/registrations/_credit.html.erb where line #2 raised:
undefined local variable or method `resource' for #<#<Class:0x00563138834928>:0x00563138821670>
In app/models/order.rb:
class Order < ActiveRecord::Base
belongs_to :user
# only use this if user instance is created before order,
# and alway associated with order
validates :user, presence: true
end
In app/models/user.rb:
class User < ActiveRecord::Base
has_many :orders
# --OR--
# has_one :order
end
In app/controllers/orders_controller.rb:
class OrdersController < ApplicationController
# 1)assuming `current_user` is populated
#
def new
#order = Order.new
#user = current_user
end
# --OR--
# 2) assuming the following line is in `config/routes.rb`:
# get '/orders/new/:id' => 'orders#new'
#
def new
if #order = Order.find_by_id(new_params[:id])
#user = #order.user
else
# do whatever here; replace the next line
raise "order not found"
end
end
private
# only needed for 2) above
def new_params
params.permit(:id)
end
end
see: http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters
In app/view/orders/new.html.erb:
<% raise('#user not defined') unless #user %><%# <- Remove this line after partial is working %>
<%= render partial: "devise/registrations/credit", locals: {resource: #user, resource_name: :user} %>
see: http://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables

Rails 4 - associations between controllers, id not getting passed

I have two controllers categories and products. Products belongs to categories but I'm having trouble setting up the relationship.
In category.rb
has_many :products
In product.rb
belongs_to :category
validates :category_id, :presence => true
validates :name, :presence => true, :uniqueness => true
When I try to create a new product, the record does not save because category_id is blank. My product form looks like so:
<%= form_for #product, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.hidden_field('category_id', :value => params[:category_id]) %>
<div class="control-group">
<%= f.label :name, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :name, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :category, :class => 'control-label' %>
<div class="controls">
<% #cat = Category.all %>
<%= select_tag 'category', options_from_collection_for_select(#cat, 'id', 'name') %>
</div>
</div>
<div class="control-group">
<%= f.label :price, :class => 'control-label' %>
<div class="controls">
<%= f.text_field :price, :class => 'text_field' %>
</div>
</div>
<div class="control-group">
<%= f.label :description, :class => 'control-label' %>
<div class="controls">
<%= f.text_area :description, :class => "tinymce", :rows => 10, :cols => 120 %>
<%= tinymce %>
</div>
</div>
<div class="form-actions">
<%= f.submit nil, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
products_path, :class => 'btn' %>
</div>
<% end %>
and in the products controller I have:
def new
#product = Product.new
#category = #product.category
end
I've tried looking through other questions on SO but haven't had any luck finding the correct way to pass the category id to products.
I hope I've been clear enough and I'm happy to provide any extra information that may be needed.
EDIT
I've made the following changes to the products controller as suggested by I not get the error: Cannot find Category without an ID
before_filter :set_category, only: [:create]
def set_category
#category = Category.find(params[:category_id])
end
def create
#product = #category.products.new(product_params)
#....
end
I'm using nested routes like so:
resources :categories do
resources :products
end
You should set product's category in create action:
def create
#product = #category.products.new(product_params)
# ...
end
in new action, you should just have
def create
#product = Product.new
end
Of course, you need to set #category (#category = Category.find(params[:category_id])) instance variable before (in before_filter, for example).
You should also remove this hidden field from view and remove category_id from allowed params if you don't want users to set category_id manually and set form_for arguments properly, since you're using nested resources:
form_for [#category, #product]

Nested form not appearing (simple_form)

I have a model named Page and one named Medium. Medium is for uploaded images. The two models are connected with a rich HABTM association.
I want to be able to upload images through my page edit form. However i got a strange result. I am only getting the file field when the page already have an image associated with it. What can cause this?
This is my page model:
class Page < ActiveRecord::Base
attr_accessible :content, :title, :url, :status, :excerpt, :media_attributes
belongs_to :users
has_many :page_medium
has_many :media, :through => :page_medium
accepts_nested_attributes_for :media
acts_as_url :title, :only_when_blank => true, :sync_url => true
acts_as_list
STATUS = %w[draft published]
def to_param
"#{url}" # or whatever you set :url_attribute to
end
validates :title, :status, :url, :presence => true
end
This is my form:
<%= simple_form_for #page, :html => { :class => 'page-form' } do |f| %>
<div class="span9">
<div class="row">
<%= f.input :title, input_html: { class: 'span6'}, wrapper_html: { class: 'span6'} %>
<%= f.input :url, input_html: { class: 'span3'}, wrapper_html: { class: 'span3'} %>
</div>
<div class="tabbable"> <!-- Only required for left/right tabs -->
<ul class="nav nav-tabs">
<li class="active">Content</li>
<li>Excerpt</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab1">
<%= f.input :content, label: false, input_html: { class: 'wysihtml5 span9' } %>
</div>
<div class="tab-pane" id="tab2">
<%= f.input :excerpt, label: false, input_html: { class: 'wysihtml5 span9 excerpt' }%>
</div>
</div>
</div>
</div>
<div class="span3">
<div class="well">
<fieldset>
<legend>Options</legend>
</fieldset>
<%= f.input :status , collection: Page::STATUS.map { |s| [s.humanize, s] }, prompt: '- Select page status -' %>
<div class="form-actions">
<%= f.button :submit, :class => 'btn btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
pages_path, :class => 'btn' %>
</div>
</div>
</div>
<div class="span9">
<%= f.simple_fields_for :media do |m| %>
<%= m.input :image, as: :file %>
<% end %>
</div>
<% end %>
<%= render :partial => 'display_images' %>
Please comment if you need any more information or code. All tips, answers or constructive comments are appreciated. :)
this code:
<%= f.simple_fields_for :media do |m| %>
<%= m.input :image, as: :file %>
<% end %>
will only allow you to update the images you already have.
To add more images I suggest you follow this episode of railscast: http://railscasts.com/episodes/196-nested-model-form-revised

Resources