How do I build a nested form in Refinerycms? - refinerycms

I am trying to nest a form with two resources (Map and Location).
I'm following the Nested Forms tutorial from Ryan Bates however I must be missing something.
Map Model:
module Refinery
module Maps
class Map < Refinery::Core::BaseModel
self.table_name = 'refinery_maps'
attr_accessible :name, :position, :questions_attributes
validates :name, :presence => true, :uniqueness => true
has_many :locations
accepts_nested_attributes_for :locations
end
end
end
Location Model:
module Refinery
module Maps
class Location < Refinery::Core::BaseModel
attr_accessible :latitude, :longitude, :address, :description, :title, :position
validates :address, :presence => true, :uniqueness => true
belongs_to :map
end
end
end
View:
Controller(decorator):
Refinery::PagesController.class_eval do
before_filter :new
private
def new
#map = Map.new
3.times { #map.locations.build }
end
end
Schema:
create_table "refinery_maps_locations", :force => true do |t|
t.float "latitude"
t.float "longitude"
t.string "address"
t.string "description"
t.string "title"
t.integer "position"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "map_id"
end
create_table "refinery_maps", :force => true do |t|
t.string "name"
t.integer "position"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
Routes:
Refinery::Core::Engine.routes.draw do
# Frontend routes
namespace :maps do
resources :maps, :path => '', :only => [:index, :show]
end
# Admin routes
namespace :maps, :path => '' do
namespace :admin, :path => Refinery::Core.backend_route do
resources :maps, :except => :show do
collection do
post :update_positions
end
end
end
end
# Frontend routes
namespace :maps do
resources :locations, :only => [:index, :show]
end
# Admin routes
namespace :maps, :path => '' do
namespace :admin, :path => "#{Refinery::Core.backend_route}/maps" do
resources :locations, :except => :show do
collection do
post :update_positions
end
end
end
end
end

You are missing a :locations_attributes in your Map model - you have :questions_attributes there instead.
Also, check out this gem for refinerycms nested models - https://github.com/llamadigital/refinerycms-nested_models
Just replace "nested_models" with the name of the one you want to nest. It works much better with refinery than nested forms.

Related

cannot save data using a nested form with the cocoon gem

I am having trouble saving data using a nested form with the cocoon gem, and haven't been able to find a solution on SO.
I have two models: Requests has_many Votes.
I would like to create a single form that saves a new request, and a new vote simultaneously. The issue is that currently neither a new request nor a new vote is saved using the below code. I've pasted the terminal output below for completeness.
Terminal output:
Started POST "/requests" for ::1 at 2015-06-25 15:41:17 +0100
Processing by RequestsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"FCHcO1RLg2zr6mo8MpmVNMEasvPrAqyHAY5d2SdrlDUn83ppnsRhQUU33YiOZ84c4z1xMYQI4gzjLymN1NL3fw==", "request"=>{"firstname"=>"sdf", "lastname"=>"sf", "email"=>"sdf#lskdjf.com", "request"=>"lskdj", "description"=>"sldkjf", "votes_attributes"=>{"1435243272926"=>{"comment"=>"sadflkj", "email"=>"lkfj#sldk.com", "beta"=>"1", "_destroy"=>""}}}, "commit"=>"Save"}
(0.2ms) begin transaction
Vote Exists (0.2ms) SELECT 1 AS one FROM "votes" WHERE LOWER("votes"."email") = LOWER('lkfj#sldk.com') LIMIT 1
Request Exists (0.1ms) SELECT 1 AS one FROM "requests" WHERE LOWER("requests"."email") = LOWER('sdf#lskdjf.com') LIMIT 1
(0.1ms) rollback transaction
Rendered requests/_vote_fields.html.haml (0.9ms)
Rendered requests/_vote_fields.html.haml (1.0ms)
Rendered requests/_form.html.haml (8.4ms)
Rendered requests/new.html.erb within layouts/application (9.2ms)
Completed 200 OK in 118ms (Views: 105.8ms | ActiveRecord: 0.5ms)
Models:
class Request < ActiveRecord::Base
has_many :votes, dependent: :destroy
accepts_nested_attributes_for :votes
end
class Vote < ActiveRecord::Base
belongs_to :request
end
Requests controller
class RequestsController < ApplicationController
before_action :set_request, only: [:show, :edit, :update, :destroy]
def create
#request = Request.new(request_params)
if #request.save
redirect_to #request
else
render 'new'
end
end
private
def set_request
#request = Request.find(params[:id])
end
def request_params
params.require(:request).permit(
:id, :firstname, :lastname, :email, :request, :description, :votes, :tag_list,
votes_attributes: [:firstname, :lastname, :email, :comment, :beta, :id, :_destroy] )
end
end
requests/_form.html
= form_for(#request) do |f|
.field= f.text_field :firstname, placeholder: "Requester firstname"
.field= f.text_field :lastname, placeholder: "Requester Lastname"
.field= f.text_field :email, placeholder: "Email"
.field= f.text_field :request, placeholder: "Request"
.field= f.text_field :description, placeholder: "Description"
#votes
= f.fields_for :votes do |vote|
= render 'votes/vote_fields', :f => vote
.links
= link_to_add_association 'add vote', f, :votes, :render_options => { :wrapper => 'inline' }, partial: 'votes/vote_fields'
.action= f.submit "Save"
requests/_votes_fields.html.haml
.nested-fields
.form-inline
= f.text_field :comment, :placeholder => 'comment'
= f.text_field :email, :placeholder => 'email'
= f.check_box :beta, :placeholder => 'beta', :as => :boolean
.links
= link_to_remove_association "remove vote", f
votes and model validations:
vote.rb
belongs_to :request
before_save { self.email = email.downcase } #to ensure email uniqueness
validates :email, presence: true, length: { maximum: 250 }, uniqueness: { case_sensitive: false }
validates :request_id, presence: :true
request.rb
belongs_to :user
has_many :votes, dependent: :destroy
accepts_nested_attributes_for :votes
before_save { self.email = email.downcase }
validates :request, presence: true
validates :firstname, presence: true, length: { maximum: 50 }
validates :lastname, presence: true, length: { maximum: 50 }
validates :email, presence: true, length: { maximum: 250 }, uniqueness: { case_sensitive: false }
acts_as_taggable

Rails Create has_many_through won't create records

I am creating an exercise tracking website that has a Workout table, a WorkoutExercise table, and an Exercise table (this is just some of the schema).
I have been trying to create a "WorkoutExercise" from the Edit / create Workout form. I'm using Formtastic and my form displays the list of exercises for the user, but when I submit the form, no WorkoutExercises get created, but the workout does get created or updated.
I've searched google and stackoverflow for this issue for a day and a half with not much help. From what I can tell, this should "just work", I think I've missed something simple. This is my first RoR website, so please bear with me:)
Another thing to note, if I manually create the relationship in PSQL, the exercises that I create a relation for show up checked, but when I hit submit, the WorkoutExercise records are deleted from the database.
Database Schema for these 3 tables:
create_table "exercises", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.text "notes"
t.decimal "base_weight"
end
create_table "workout_exercises", force: true do |t|
t.integer "workout_id"
t.integer "exercise_id"
t.integer "exercise_order"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "workouts", force: true do |t|
t.integer "user_id"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
Exercise Model:
class Exercise < ActiveRecord::Base
has_many :weight_logs, dependent: :destroy
belongs_to :user
has_many :workout_exercises
has_many :workouts, :through => :workout_exercises
...
WorkoutExercise Model (Many to many table)
class WorkoutExercise < ActiveRecord::Base
belongs_to :exercise
belongs_to :workout
accepts_nested_attributes_for :workout
#default_scope -> { order('exercise_order ASC') }
validates :exercise_id, presence: true
validates :workout_id, presence: true
validates :exercise_order, presence: true
end
Workout Model:
class Workout < ActiveRecord::Base
has_many :workout_exercises
has_many :exercises, :through => :workout_exercises, :class_name => 'Exercise'
belongs_to :user
accepts_nested_attributes_for :exercises
accepts_nested_attributes_for :workout_exercises
...
Workouts_conroller.rb
class WorkoutsController < ApplicationController
before_action :set_workout, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
before_action :correct_user, only: :destroy
# GET /workouts
# GET /workouts.json
def index
#workouts = Workout.all
end
# GET /workouts/1
# GET /workouts/1.json
def show
end
def add_exercise
end
# GET /workouts/new
def new
#workout = current_user.workouts.new
#exercises = current_user.exercises.all
end
# GET /workouts/1/edit
def edit
#exercises = #workout.exercises.build
end
# POST /workouts
# POST /workouts.json
def create
#workout = current_user.workouts.build(workout_params)
respond_to do |format|
if #workout.save
format.html { redirect_to #workout, notice: 'Workout was successfully created.' }
format.json { render :show, status: :created, location: #workout }
else
format.html { render :new }
format.json { render json: #workout.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /workouts/1
# PATCH/PUT /workouts/1.json
def update
respond_to do |format|
if #workout.update(workout_params)
format.html { redirect_to #workout, notice: 'Workout was successfully updated.' }
format.json { render :show, status: :ok, location: #workout }
else
format.html { render :edit }
format.json { render json: #workout.errors, status: :unprocessable_entity }
end
end
end
# DELETE /workouts/1
# DELETE /workouts/1.json
def destroy
#workout.destroy
respond_to do |format|
format.html { redirect_to workouts_url, notice: 'Workout was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_workout
#workout = Workout.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def workout_params
params.require(:workout).permit(:description, :name,
:exercise_ids => [:exercise_id])
end
def correct_user
#workout = current_user.workouts.find_by(id: params[:id])
redirect_to root_url if #workout.nil?
end
end
Rails Server log on Save:
Started PATCH "/workouts/6" for 127.0.0.1 at 2014-07-13 19:30:05 -0700
Processing by WorkoutsController#update as HTML
Parameters: {"utf8"=>"v", "authenticity_token"=>"WY2P1Z7/g/PoG5iB6VufDNOG7Hyk7tnJQzTT00CpNTM=", "workout"=>{"name"=>"sad", "description"=>"asd", "exercise_ids"=>["", "17", "23",
"9", "15", "14", "18"]}, "commit"=>"Update Workout", "id"=>"6"}
?[1m?[36mWorkout Load (0.0ms)?[0m ?[1mSELECT "workouts".* FROM "workouts" WHERE "workouts"."id" = $1 LIMIT 1?[0m [["id", 6]]
?[1m?[35mUser Load (1.0ms)?[0m SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
?[1m?[36m (0.0ms)?[0m ?[1mBEGIN?[0m
?[1m?[35mExercise Load (0.0ms)?[0m SELECT "exercises".* FROM "exercises" INNER JOIN "workout_exercises" ON "exercises"."id" = "workout_exercises"."exercise_id" WHERE "workout_ex
ercises"."workout_id" = $1 ORDER BY name ASC [["workout_id", 6]]
?[1m?[36m (0.0ms)?[0m ?[1mCOMMIT?[0m
Redirected to http://localhost:3000/workouts/6
And here's my form too:
<%= semantic_form_for #workout do |f| %>
<%= f.inputs do %>
<%= f.input :name %>
<%= f.text_area :description %>
<%= f.input :exercises, :as => :check_boxes, :collection => Exercise.where(:user_id => #workout.user_id) %>
<% end%>
<%= f.actions %>
<% end %>
EDIT
I'm unable to answer my question, but I've found a workaround. I don't think this is the best solution, but it works! This was added in the def update of my workouts_controller.rb
if #workout.update(workout_params)
params[:workout].each do |key,value|
if key == 'exercise_ids'
#exercises = Exercise.find(value.reject!{|a| a==""})
#workout.exercises << #exercises
end
end

ActiveRecord cannot delete a record

I have my AttachmentsMembers table with the migration as:
class AttachmentsMembers < ActiveRecord::Migration
def change
create_table :attachments_members, :id => false do |t|
t.references :attachment, :null => false
t.references :member, :null => false
end
add_index :attachments_members, [:attachment_id, :member_id]
end
end
If I try to delete any record from my console then I get the following error:
ActiveRecord::StatementInvalid: PG::Error: ERROR: zero-length delimited identifier at or near """"
LINE 1: ...OM "attachments_members" WHERE "attachments_members"."" = $1
^
: DELETE FROM "attachments_members" WHERE "attachments_members"."" = $1
from /home/icicle/.rvm/gems/ruby-2.0.0-p353#ltbuddy/gems/activerecord-3.2.18/lib/active_record/connection_adapters/postgresql_adapter.rb:1208:in `prepare
Code for AttachmentsMember model:
class AttachmentsMember < ActiveRecord::Base
#Relationships
belongs_to :attachment
belongs_to :member
end
In attachment model:
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
belongs_to :attachable, polymorphic: true
belongs_to :referable, polymorphic: true
has_many :attachments, as: :referable, :dependent => :destroy
has_many :attachments_members, :dependent => :destroy
has_many :members, :through => :attachments_members, :dependent => :destroy
In member model:
belongs_to :user, class_name: 'User', foreign_key: 'user_id'
belongs_to :case, class_name: 'Case', foreign_key: 'case_id'
belongs_to :user_type, class_name: 'UserType', foreign_key: 'user_type_id'
has_many :attachments_members, dependent: :destroy
has_many :attachments, :through => :attachments_members, dependent: :destroy
has_many :documents_members, dependent: :destroy
has_many :documents, :through => :documents_members, dependent: :destroy
Even if do AttachmentsMember.last from my console I get the same error but AttachmentsMember.first works.
Any someone explain why the issue is coming?
Resolved the issue by creating the primary key for AttachmentsMember table

Calling Document.find with nil is invalid in mongodb

I am using mongodb with active merchant gem in rails4. While use rails cast tutorial #145 Integrating Active Merchant.
Error
Problem: Calling Document.find with nil is invalid. Summary: Document.find expects the parameters to be 1 or more ids, and will return a single document if 1 id is provided, otherwise an array of documents if multiple ids are provided. Resolution: Most likely this is caused by passing parameters directly through to the find, and the parameter either is not present or the key from which it is accessed is incorrect.
Order Controller
class OrderController < ApplicationController
include ActiveMerchant::Billing::Integrations
def new
#cart = current_cart
#order = Order.new
end
def success
end
def failure
end
def create
#order = current_cart.build_order(params_order)
#order.ip_address = request.remote_ip
if #order.save
if #order.purchase
render :action => "success"
else
render :action => "failure"
end
else
render :action => 'new'
end
end
private
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
def params_order
params.require(:order).permit(:first_name, :last_name, :card_type, :card_number, :card_verification, :card_expires_on)
end
end
Model
order.rb
class Order < ActiveRecord::Base
belongs_to :cart
has_many :transactions, :class_name => "OrderTransaction"
attr_accessor :card_number, :card_verification
#validate_on_create :validate_card
def purchase
response = GATEWAY.purchase(price_in_cents, credit_card, purchase_options)
transactions.create!(:action => "purchase", :amount => price_in_cents, :response => response)
cart.update_attribute(:purchased_at, Time.now) if response.success?
response.success?
end
def price_in_cents
return 100 #(cart.total_price*100).round
end
private
def purchase_options
{
:ip => ip_address,
:billing_address => {
:name => "Ryan Bates",
:address1 => "123 Main St.",
:city => "New York",
:state => "NY",
:country => "US",
:zip => "10001"
}
}
end
def validate_card
unless credit_card.valid?
credit_card.errors.full_messages.each do |message|
errors.add_to_base message
end
end
end
def credit_card
#credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:type => card_type,
:number => card_number,
:verification_value => card_verification,
:month => card_expires_on.month,
:year => card_expires_on.year,
:first_name => first_name,
:last_name => last_name
)
end
end
order_transaction.rb
class OrderTransaction
include Mongoid::Document
field :order_id, type: Integer
field :action, type: String
field :amount, type: Integer
field :success, type: Mongoid::Boolean
field :authorization, type: String
field :message, type: String
field :params, type: String
end
cart.rb
class Cart
include Mongoid::Document
has_one :order
end
Route.rb File
get "order/new"
get "order/success"
get "order/failure"
post "order/create", :to => "order#create", as: :orders
resources :cart do
resource :order
end
View
new.html.haml
%br
%br
%h5.text-center
= " Order "
=form_for :order, url:{action: "create"}, html:{class: "form-horizontal"} do |f|
%div.form-group
=f.label :first_name, 'First Name' , {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.text_field :first_name, {:class => 'form-control', :placeholder => "First Name"}
%div.form-group
=f.label :last_name, 'Last Name', {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.text_field :last_name, {:class => 'form-control', :placeholder => "Last Name"}
%div.form-group
=f.label :card_type, 'Card Type', {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.select(:card_type, [["Visa", "visa"], ["MasterCard", "master"], ["Discover", "discover"], ["American Express", "american_express"]], {}, {:class => 'form-control', :placeholder => ""})
%div.form-group
=f.label :card_number, 'Card Number', {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.text_field :card_number, {:class => 'form-control', :placeholder => "378282246310005"}
%div.form-group
=f.label :card_verification, 'Card Verification', {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.text_field :card_verification, {:class => 'form-control', :placeholder => "YES"}
%div.form-group
=f.label :card_expires_on, 'Card Expire Date', {:class => 'col-lg-2 control-label'}
%div.col-lg-3
=f.date_select :card_expires_on, :discard_day => true, :start_year => Date.today.year, :end_year => (Date.today.year+10), :add_month_numbers => true
%div.form-group
%div.col-lg-offset-2.col-lg-10
=f.submit :class => 'btn btn-primary'
Error Occur
Mongoid::Errors::InvalidFind in OrderController#new
Problem: Calling Document.find with nil is invalid. Summary: Document.find expects the parameters to be 1 or more ids, and will return a single document if 1 id is provided, otherwise an array of documents if multiple ids are provided. Resolution: Most likely this is caused by passing parameters directly through to the find, and the parameter either is not present or the key from which it is accessed is incorrect.
** Your suggestion will helpful. Thanks in advanced**
OrderController#new calls OrderController#current_cart which runs Cart.find(session[:cart_id]). There's no :cart_id at session start, i.e., session[:cart_id] is nil, and you get the Mongoid::Errors::InvalidFind exception above. Note that your rescue clause will not rescue that exception as you are rescuing ActiveRecord::RecordNotFound. You are using Mongoid, not ActiveRecord, and must program accordingly. Best wishes.

Active admin not showing all input fields just last one

I have this code inside app/admin/products.rb. I have problem with that I can see just one input field at time(the last one listed) or just submit button. Does it could be because of some syntax mistakes ? But there is no any error messages.
ActiveAdmin.register Product do
f.input :name,:label => "Name"
f.input :photo, :as => :file
f.input :category, :collection => #category
f.input :manufacturer, :collection => #manufacturer
f.actions do
f.action :submit, :button_html => { :class => "primary", :disable_with => 'Wait...' }
end
end
end
Product model looks like this
attr_accessible :category_id, :description, :manufacturer_id, :name, :photo
extend FriendlyId
has_attached_file :photo,
:styles => {
:thumb=> "100x100#",
:large => "290x170",
:medium=> "120x120"}
friendly_id :name, use: [:slugged, :history]
belongs_to :manufacturer
belongs_to :category
Your form should be inside the block.
Example
ActiveAdmin.register Post do
form do |f|
f.inputs "Details" do
f.input :title
f.input :published_at, :label => "Publish Post At"
f.input :category
end
f.inputs "Content" do
f.input :body
end
f.actions
end
end
Here is more info
http://activeadmin.info/docs/5-forms.html