Making one nested form_for use two different controllers - ruby-on-rails

I have two models #product and #photo with #photo nested in #product. I am only allowed to use one form to create both. I am using this JQuery plugin to handle photo upload being how it gives me a nice preview.
However the plugin has certain restrictions in my create action so I cannot use the product create action to handle both creating the photo and product.
Is it possible to have one nested for_for use two different controllers?
And how would i do it ?
my form (haml)
= form_for #product,:url => products_path, :html => { id: "fileupload", multipart: true } do |f|
%p
= f.text_field :name, placeholder: "Name"
%p
= f.text_field :price, class: "auto", data: { a_sign: "$ " }, placeholder: "Price"
%p
= f.text_field :description, placeholder: "Description"
%p
= f.fields_for :photos do |fp|
=fp.file_field :image
%br
.files{"data-target" => "#modal-gallery", "data-toggle" => "modal-gallery"}
%p.button.start
= f.submit

You can use accept_nested_attributes for to save associated data with only one create action.
Eg:-
class AlbumsController < ApplicationController
def new
#album = Album.new
#album.photos.build
end
def create
#album = Albums.new(params[:album])
#album.photos.build unless #album.photos.present?
if #album.save
flash[:notice] = "Successfully created albumn"
respond_with(#album, :location => albums_path())
else
flash[:error] = #album.errors.full_messages
render :new
end
end
end
Model:-
class Album < ActiveRecord::Base
has_many :photos, dependent: :destroy
accepts_nested_attributes_for :photos, allow_destroy: true, reject_if: proc {|attr| attr['image'].blank? }
end
class Photo < ActiveRecord::Base
belongs_to :album
end
View:-
= form_for #album,:url => albums_path, :html => {multipart: true } do |f|
%p
= f.text_field :name, placeholder: "Name"
%p
= f.text_field :price, class: "auto", data: { a_sign: "$ " }, placeholder: "Price"
%p
= f.text_field :description, placeholder: "Description"
%p
= f.fields_for :photos do |photo|
= photo.file_field :image
%br
.files
%p.button.start
= f.submit

Use ajax to firstly upload photo and after successful response continue with product.

Related

Select and save multiple Checkboxes with simple for

I'm trying to implement a multiple select and save with simple form and nested forms.
My view shows all the branches with name and description in a card format (Bootstrap). Next to te name I would like to have a checkbox. I would like to save only the selected ones
= simple_form_for(#my_branch, html: { class: 'form-horizontal' }) do |f|
= f.error_notification
= f.input :user_id, input_html: { value: current_user.id}, as: :hidden
- #branches.each do |branch|
= f.simple_fields_for :my_branch_items do |b|
.col-md-4
.card{:style => "width: 18rem;"}
.card-header
= branch.name
= b.input :branch_id, input_html: { value: branch.id }, as: :radio_buttons
%ul.list-group.list-group-flush
= branch.description
.form-group
= f.submit 'Save', class: 'btn btn-primary'
Here are the associations
class Branch < ApplicationRecord
has_many :my_branch_items
end
class MyBranch < ApplicationRecord
belongs_to :user
has_many :my_branch_items
accepts_nested_attributes_for :my_branch_items, allow_destroy: true, reject_if: proc { |att| att['name'].blank? }
end
class MyBranchItem < ApplicationRecord
belongs_to :my_branch
belongs_to :branch
end
And the Controller
class MyBranchesController < BaseController
before_action :set_my_branch, only: [:show]
def new
#branches = Branch.all
#my_branch = MyBranch.new
end
def create
#my_branch = Quiz.new(my_branch_params)
if #my_branch.save
redirect_to my_branch_path(#my_branch), notice: 'Thanks for taking the Branch Quiz'
else
render :new
end
end
def show
end
private
def set_my_branch
#my_branch = MyBranch.find(params[:id])
end
def my_branch_params
params.require(:my_branch).permit(:name, :note, :user_id, my_branch_items_attributes: MyBranchItem.attribute_names.map(&:to_sym).push(:_destroy))
end
end
Fixed!
Form
= simple_form_for(#my_branch, html: { class: 'form-horizontal' }) do |f|
= f.error_notification
= f.input :user_id, input_html: { value: current_user.id}, as: :hidden
- #branches.each do |branch|
= f.simple_fields_for :my_branch_items do |b|
.col-md-4
.card{:style => "width: 18rem;"}
.card-header
= branch.name
= b.input_field :branch_id, checked_value: branch.id, as: :boolean, boolean_style: :inline, include_hidden: false
%ul.list-group.list-group-flush
= branch.description
.form-group
= f.submit 'Save', class: 'btn btn-primary'
Model was using a validation for blanks field that did not exist in the table.
class MyBranch < ApplicationRecord
belongs_to :user
has_many :my_branch_items, dependent: :destroy
accepts_nested_attributes_for :my_branch_items, allow_destroy: true, reject_if: proc { |att| att['branch_id'].blank? }
end

first element in form can't be blank

I've got this problem
.container.weekdays
.row
.col-sm-3
.panel-default data-day="#{#weekdays[0]}"
.h3
|Today's menu.
=#weekdays[0]
br
=link_to "Today's menu", admin_menu_path("#{#weekdays[0]}"), class: 'today', remote: true
hr
hr
fieldset
legend Update menu here
=form_for [:admin, #menu] ,method: :patch, remote: true do |f|
p
= f.select(:type, options_for_select(["", :First, :Second, :Drink], include_blank: true))
p
=f.label 'Name'
=f.text_field :name
p
=f.label 'Price'
=f.number_field :price
= f.submit
and menus controller, where show action is working right
class Admin::MenusController < Admin::BaseController
before_action :set_menu , only:[:update]
def show
#menu = Menu.where(day: params[:id])
end
def update
#menu = Menu.where(day: DateTime.now.strftime("%A"))
#item = menu_params.type.constantize.new(name: menu_parms.name, price: params[:menu][:price], menu: #menu)
#item.save
end
private
def menu_params
params.require(:menu).permit(:type, :name, :price)
end
end
I am recieving first argument cn't be nill in form update, need some help n that. I do undestand that code is awful but still I am a newcommer it should work first than I'll try to refact
To better understand the problem here is menu model
class Menu < ApplicationRecord
has_many :dishes
delegate :firstmeals, :secondmeals, :drinks, to: :dishes
validates :day, presence: true
validates :day, uniqueness: true
def self.get_menu day
Menu.where(day: day).first
end
private
def to_param
day
end
end
So I do not actually need to update menu, I need only to create a dish. But the same problemm still exist
fieldset
legend Update menu here
=form_for [:admin, #dish], method: :patch, remote: true do |f|
p
= f.select(:type, options_for_select(["", :First, :Second, :Drink], include_blank: true))
p
=f.label 'Name'
=f.text_field :name
p
=f.label 'Price'
=f.number_field :price
= f.submit
include_blank should be outside of options_for_select
= f.select(:type, options_for_select([:First, :Second, :Drink]), { include_blank: true })
If you are passing include_blank option you don't need to add empty string manually
documentation for select

Rails 4 Nested Resources, Forms, strong params

I am trying to create a workout tracker. I have these nested resources
Routes.rb
resources :days do
resources :workouts
resources :meals
end
My models look fine:
Workout.rb
class Workout < ActiveRecord::Base
has_many :exercises
belongs_to :day
end
Day.rb
class Day < ActiveRecord::Base
has_many :workouts
has_many :meals
accepts_nested_attributes_for :workouts, :allow_destroy => true
accepts_nested_attributes_for :meals, :allow_destroy => true
end
The issue lies when I try to create a new workout..
../views/workouts/_form.html.haml
= form_for([#day, #workout]), html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.hidden_field :day_id, value: params[:day_id], input_html: { class: "form-control"}
= f.submit
I cant seem to save the :day_id the workout is associated with the workout though using strong params to receive them.
WorkoutsController.rb
private
def workout_params
params.require(:workout).permit(:day_id, :name, :mood)
end
def find_day
#day = Day.find(params[:day_id])
end
Instead what gets saved is a nil for :day_id
Rails Console:
Workout id: 11, name: "Hey", mood: "no", day_id: nil, created_at: "2014-12-19 14:53:29", updated_at: "2014-12-19 14:53:29"
HELP?
PS - i tried to do
= form_for([#day, #workout]), as: :foo, html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.hidden_field :day_id, value: params[:day_id], input_html: { class: "form-control"}
= f.submit
and then
def workout_params
params.require(:foo).permit(:day_id, :name, :mood)
end
But it just kept saying the :foo params where empty
The way your routes are set up, I am assuming that the day_id is being passed as a url params:
/days/:day_id/workouts
If that is the case, then you do not need to worry about #day in the form, nor the day_id in the workout_params
Form:
= form_for #workout, html: {class: 'form-horizontal'}) do |f|
= f.input :workout, label: "What did you work out", input_html: { class: "form-control"}
= f.input :mood, label: "How do you feel", input_html: { class: "form-control"}
= f.submit
Controller:
def create
#workout = #day.workouts.new(workout_params)
....
end
private
def workout_params
params.require(:workout).permit(:name, :mood)
end
def find_day
#day = Day.find(params[:day_id])
end

Extract search functionality to Form Object in Rails

In my Rails application I have simple search functionality. I want to extract to Form Object but don't know how to do. I have search form which looks like this:
.row
= horizontal_simple_form_for :cars, {url: cars_path, method: :get} do |f|
.col-md-4
.row
.col-md-12
= f.input :handover_location, label: I18n.t('.handover'), collection: Location.all.map{|hl| [hl.location_address, hl.id]}
= f.input :return_location, label: I18n.t('.return') ,collection: Location.all.map{|rl| [rl.location_address, rl.id]}
= f.input :car_class, label: I18n.t('.car_class') ,collection: CarClass.all.map { |c| [c.name, c.id] }, include_blank: true
.col-md-4
= f.input :handover_date, as: :string, label: false
= f.input :return_date, as: :string, label: false
= f.submit class: 'btn btn-success'
Cars controller:
class CarsController < ApplicationController
skip_authorization_check
def index
#cars = Car.search(params)
end
def show
end
end
And class method in Car model which search correct cars:
def self.search(params)
self.joins(:reservations).where.not("reservations.reception_time <= ? AND reservations.return_time >= ?",
params[:cars][:return_date], params[:cars][:handover_date]).
joins(:car_class).where("car_classes.id= ?", params[:cars][:car_class])
.cars_at_both_locations(params[:cars][:handover_location], params[:cars][:return_location])
end
Now I'm trying to extract this to Form Object. I've created a file search_form.rb:
class SearchForm
include ActiveModel::Model
attr_accessor :handover_date, :return_date, :handover_location, :return_location, :car_class
end
But now I don't know how to handle my params to this form object. Thank's in advance.
I wish I could help you with the Form Object stuff, but I need to learn more about classes & modules
I can help you with the search functionality, as we've done it before here
Here's the code we used:
#View
<%= form_tag search_path, :method => :post, :id => "SearchForm" do %>
<%= text_field_tag :search, params[:search], placeholder: 'Search your favourite products or brands', :autocomplete => :off %>
<%= image_submit_tag 'nav_bar/search.png' %>
<% end %>
#config/routes.rb
match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]
#app/controllers/products_controller.rb
def search
#products = Product.search(params[:search])
respond_to do |format|
format.js { render :partial => "elements/livesearch", :locals => {:search => #products, :query => params[:search]} }
format.html { render :index }
end
end
Notice the form_tag we used?
Simple form does not work with form_tag currently (it requires an object) - we just send the data with a GET request to the controller & that then sends the data to the Product model
I think your problem will be caused by the use of your SearchForm object. You only need this because your use of simple form means you have to pass an object. Problem being this is not necessary for search
A better way will be to use a standard form_tag, and send the request directly to your controller. This will allow you to process the data as params, which you'll be able to send directly to your Car model
--
I can write some code specific to you if you want
I found solution on my own.
Cars controller:
def index
#search_form = SearchForm.new(params[:search_form])
#cars = #search_form.submit(params[:search_form])
end
search_form.rb:
class SearchForm
include ActiveModel::Model
attr_accessor :handover_date, :return_date, :handover_location, :return_location, :car_class
def submit(params)
Car.search(params)
end
end
Search form in view:
.row
= horizontal_simple_form_for SearchForm.new, {url: cars_path, method: :get} do |f|
.col-md-4
.row
.col-md-12
= f.input :handover_location, label: I18n.t('.handover'), collection: Location.all.map{|hl| [hl.name, hl.id]}
= f.input :return_location, label: I18n.t('.return') ,collection: Location.all.map{|rl| [rl.name, rl.id]}
= f.input :car_class, label: I18n.t('.car_class') ,collection: CarClass.all.map { |c| [c.name, c.id] }, include_blank: true
.col-md-4
= f.input :handover_date, as: :string, label: false
= f.input :return_date, as: :string, label: false
= f.submit class: 'btn btn-success'
search method in car model:
def self.search(params)
self.joins(:reservations).where.not("reservations.reception_time <= ? AND reservations.return_time >= ?",
params[:return_date], params[:handover_date]).
joins(:car_class).where("car_classes.id= ?", params[:car_class])
.cars_at_both_locations(params[:handover_location], params[:return_location])
end

rails 3 accepts_nested_attributes_for not rejecting empty nested file_field

New to rails and I'm trying to reject an empty nested file_field but it just keeps going though. Here is the setup.
EDIT: It does actually save the image properly if one is included, just doesn't reject the empty ones.
Fihish Model
class Finish < ActiveRecord::Base
default_scope order('finishes.id ASC')
attr_accessible :name,
:title,
##belongs_to##
:sku_id,
##has_many##
:image_attributes
belongs_to :skus
has_one :image, as: :imageable, :dependent => :destroy
accepts_nested_attributes_for :image, :reject_if => lambda { |a| a[:asset].blank? }, :allow_destroy => true
validates_presence_of :title
before_save :create_name
private
def create_name
self.name = title.parameterize
end
end
Finishes Controller
def new
#finish = Finish.new
#finish.build_image
respond_to do |format|
format.html # new.html.erb
# format.json { render json: #finish }
end
end
Image Model
class Image < ActiveRecord::Base
attr_accessible :content, #remove if no longer necessary
:asset
belongs_to :imageable, polymorphic: true
mount_uploader :asset, ImageUploader
end
Form
= form_for #finish, :html => { :multipart => true } do |f|
- if #finish.errors.any?
#error_explanation
%h1= "#{pluralize(#finish.errors.count, "error")} prohibited this finish from being saved:"
%ul
- #finish.errors.full_messages.each do |msg|
%li= msg
%fieldset{id: "finishes"}
.field
= f.label :title
= f.text_field :title
#finish-image.images
= f.fields_for :image do |image_builder|
= render 'images/image_fields', f: image_builder
.actions
= f.submit 'Save'
image_fields partial
.field
= f.label :asset, "Image"
= f.file_field :asset
- if f.object.asset
.image-box
= image_tag f.object.asset_url(:thumb).to_s
.remove-fields
= link_to_remove_fields f

Resources