Rails 4 has_many through: nested model id field is not inserted - ruby-on-rails-4

I have visit and condition_value models, associated with has_many though by condition_visit.
Also, there are two other models: condition_type and condition_name. So basically there are a few conditions, each has a type and several values. When visit is created, the user chooses several values for every condition. There is also a details field for every condition.
I omitted the parts of code that seemed irrelevant.
class ConditionValue < ActiveRecord::Base
belongs_to :condition_name
has_many :visits
has_many :condition_visits, through: :visits
end
class ConditionVisit < ActiveRecord::Base
belongs_to :visit
belongs_to :condition_value
end
class Visit < ActiveRecord::Base
has_many :condition_values, through: :condition_visits
has_many :condition_visits, :dependent => :destroy
accepts_nested_attributes_for :condition_visits, :allow_destroy => true
end
controller:
class VisitsController < ApplicationController
...
def new
#visit = Visit.new
#visit.condition_visits.build
end
...
private
# Use callbacks to share common setup or constraints between actions.
def set_visit
#visit = Visit.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def visit_params
params.require(:visit).permit( ... , condition_visits_attributes:
[:details, condition_value_id:[]])
end
end
view:
<div class="field">
<% ConditionType.all.each do |type| %>
<% ConditionName.all.each do |v| %>
<% if ConditionName.find_by(:name => v.name, :condition_type_id => type.id) %>
<%= f.fields_for :condition_visits do |s| %>
<%= v.name %> <%= s.collection_select(:condition_value_id, ConditionName.find_by(:name => v.name, :condition_type_id => type.id).condition_values, :id, :name, {:include_hidden => false}, :multiple => true) %>
Details: <%= s.text_field :details %>
<% end %>
<% end %>
<br>
<% end %>
<hr>
<% end %>
The records are inserted into the DB, but only the details and visit_id fields, condition_value_id is NULL.
Log:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"eo9jxQqPk0UlPxAomDy4Njvf2+evVE/yySiaDFZMQM4Db5IvmTQ5fDK8wtxd5bTDMNfzfDBxXO+c+RdAXMjiMQ==",
"visit"=>{"condition_visits_attributes"=>{
"0"=>{"condition_value_id"=>["2", "3"], "details"=>"1"},
"1"=>{"condition_value_id"=>["13"], "details"=>"2"},
"2"=>{"details"=>""}, "3"=>{"details"=>""},
"4"=>{"details"=>""}, "5"=>{"details"=>""}, "6"=>{"details"=>""},
"7"=>{"details"=>""}, "8"=>{"details"=>""}, "9"=>{"details"=>""},
"10"=>{"details"=>""}, "11"=>{"details"=>""}, "12"=>{"details"=>""},
"13"=>{"details"=>""}, "14"=>{"details"=>""}, "15"=>{"details"=>""},
"16"=>{"details"=>""}, "17"=>{"details"=>""}, "18"=>{"details"=>""},
"19"=>{"details"=>""}, "20"=>{"details"=>""}, "21"=>{"details"=>""},
"22"=>{"details"=>""}, "23"=>{"details"=>""}, "24"=>{"details"=>""},
"25"=>{"details"=>""}, "26"=>{"details"=>""}, "27"=>{"details"=>""},
"28"=>{"details"=>""}, "29"=>{"details"=>""}}, ...,
"commit"=>"Create Visit", "doctor_id"=>"1", "patient_id"=>"14"}
....
SQL (0.2ms) INSERT INTO "condition_visits" ("details", "visit_id",
"created_at", "updated_at") VALUES (?, ?, ?, ?) [["details", "1"],
["visit_id", 236], ["created_at", "2016-03-22 13:20:46.254311"],
["updated_at", "2016-03-22 13:20:46.254311"]]
SQL (0.1ms) INSERT INTO "condition_visits" ("details", "visit_id",
"created_at", "updated_at") VALUES (?, ?, ?, ?) [["details", "2"],
["visit_id", 236], ["created_at", "2016-03-22 13:20:46.256021"],
["updated_at", "2016-03-22 13:20:46.256021"]]
SQL (0.1ms) INSERT INTO "condition_visits" ("details", "visit_id",
"created_at", "updated_at") VALUES (?, ?, ?, ?) [["details", ""],
["visit_id", 236], ["created_at", "2016-03-22 13:20:46.257165"],
["updated_at", "2016-03-22 13:20:46.257165"]]
...
How can I fix this?

Related

Issue with param not pushing data to database in Rails

Quick one. I'm trying to push a parameter into the database when i'm creating an object. I have it working if I force the integer as with the commented code below however for whatever reason I cannot get it to be added to the database is I use the params[:subscription_id] method. I can see the parameters in my server but cannot see it getting inserted into the certificates table. If i force the integer in my controller it will go through and I can see the subscriptions_id getting passed in.
Does this have any reason to do with my relationship being a has_one relationship perhaps?
Certificate Controller
class CertificatesController < ApplicationController
def new
#certificate = Certificate.new
end
def create
#certificate = Certificate.new(certificate_params)
#certificate.subscription_id = params[:subscription_id]
##certificate.subscription_id = 1
if #certificate.save
flash[:success] = "The certificate has been uploaded"
redirect_to :back
else
render 'new'
end
end
private
def certificate_params
params.require(:certificate).permit(:document, :title, :subscription_id)
end
end
View code:
<%= link_to "upload certificate", new_certificate_path(subscription_id: subscription.id) %>
Models
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :course
has_one :certificate
end
class Certificate < ActiveRecord::Base
belongs_to :subscription
has_attached_file :document
#validates_attachment :document, content_type: %w(application/pdf application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document)
do_not_validate_attachment_file_type :document
end
Certificate Form
<div class="row">
<div class="site-forms">
<div class="col-md-10">
<%= simple_form_for #certificate do |f| %>
<!-- <= f.input :course_img, as: :file, required: true, label: "Please upload a brand image for your course" %><br> -->
<span class="btn btn-default btn-file">
<i class="fa fa-cloud-upload fa-lg"></i> Upload Image
<%= f.input :document, as: :file, required: true, label: false %>
</span> Please upload Certificate as PDF <br><br>
<%= f.input :title, placeholder: "Course Title", required: true, label: "Course Title" %>
<%= f.button :submit, class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
This is probably something stupid i'm missing but I can get it to work if I force the integer in the commented out code in the controller. I'm nearly sure the params code is correct. Thanks.
Added logs
Started POST "/certificates" for ::1 at 2017-05-23 20:40:30 +0100
Processing by CertificatesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6fV0xLOoy6ppNG7PYp37vkKqJnxU17nLPSK/mvbgH8k3s2LyaMEOJlekq5S0Ed4fpbNcqVe+cBsu5F38ACCmcg==", "certificate"=>{"document"=>#<ActionDispatch::Http::UploadedFile:0x007f954362c160 #tempfile=#<Tempfile:/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/RackMultipart20170523-5261-1n2mwfl.png>, #original_filename="duck.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"certificate[document]\"; filename=\"duck.png\"\r\nContent-Type: image/png\r\n">, "title"=>"Test"}, "commit"=>"Create Certificate"}
Command :: PATH=/usr/local/bin/:$PATH; file -b --mime '/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/36846677e3a8f4c0b16d8bdf8ef1860820170523-5261-e90bny.png'
(0.1ms) begin transaction
Command :: PATH=/usr/local/bin/:$PATH; file -b --mime '/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/36846677e3a8f4c0b16d8bdf8ef1860820170523-5261-1d907er.png'
SQL (0.3ms) INSERT INTO "certificates" ("document_file_name", "document_content_type", "document_file_size", "document_updated_at", "title", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["document_file_name", "duck.png"], ["document_content_type", "image/png"], ["document_file_size", 49114], ["document_updated_at", "2017-05-23 19:40:30.662715"], ["title", "Test"], ["created_at", "2017-05-23 19:40:30.683041"], ["updated_at", "2017-05-23 19:40:30.683041"]]
(0.7ms) commit transaction
Redirected to http://localhost:3000/certificates/new?subscription_id=3
Completed 302 Found in 36ms (ActiveRecord: 1.1ms)
Started GET "/certificates/new?subscription_id=3" for ::1 at 2017-05-23 20:40:30 +0100
Processing by CertificatesController#new as HTML
Parameters: {"subscription_id"=>"3"}
Rendered certificates/_form.html.erb (7.7ms)
Rendered certificates/new.html.erb within layouts/application (8.7ms)
Rendered shared/_message.html.erb (0.1ms)
Completed 200 OK in 95ms (Views: 94.3ms | ActiveRecord: 0.0ms)
You need to set your subscription_id in a hidden field so that it gets passed in the params hash.
<%= f.hidden_field :subscription_id, :value => params[:subscription_id] %>
That way it gets set with the rest of the params.
Params are strings. Try
#certificate.subscription_id = params[:subscription_id].to_i
Try change this function as below
def certificate_params
params.require(:certificate).permit(:document, :title, :subscription_id, :subscription)
end
Maybe allow permit subscription field from params.

Mongoid/Rails has_and_belongs_to_many returning true in loop - why?

I've got two models (product and category):
class Product
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :enabled, type: Boolean
field :price, type: BigDecimal
field :sku, type: String
field :editing, type: Boolean
field :supplier, type: String
has_and_belongs_to_many :categories
has_and_belongs_to_many :subcategories
validates :name, presence: true, uniqueness: true
validates :price, presence: true
end
class Category
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :editing, type: Boolean
field :enabled, type: Boolean
has_and_belongs_to_many :subcategories
has_and_belongs_to_many :products
validates :name, presence: true, uniqueness: true
end
As you can see both have the has_and_belongs_to_many relationship. All works as expected whilst saving/retrieving data:
#products = Products.all
which will return this json:
{
_id: ObjectId("54ba495957694d4d95010000"),
category_ids: [
ObjectId("54ba494557694d4d95000000")
],
created_at: ISODate("2015-01-17T11:36:57.641Z"),
enabled: false,
name: "Product 1",
price: "23.9",
sku: "KOPP0909",
updated_at: ISODate("2015-01-17T11:36:57.641Z")
}
So far so good. In my view I'll loop through the products like so:
#products.each do |p|
p.categories.each do |c|
c.name
...
Which will return display the category name as expected. The issue I'm having is while the above code will return the category(ies) as expected it'll also print true at the end of it (in case of the object above):
Category 1 and true
What is that? How can I remove it?
As #phoet said, the pseudo code stops us from knowing exactly what is happening, but I'm going to guess that you're doing something as simple as outputting the value of your loop rather than silently looping and outputting only the categories. For example, note the equal sign in the following examples, which would output some value of the object itself, in addition to the nested output:
In ERB:
<%= for #products.each do |p| %>
<%= p.categories.each do |c| %>
<%= c.name %>
<% end %>
<% end %>
vs
<% for #products.each do |p| %>
<% p.categories.each do |c| %>
<%= c.name %>
<% end %>
<% end %>
In HAML:
= for #products.each do |p|
= p.categories.each do |c|
= c.name
vs
- for #products.each do |p|
- p.categories.each do |c|
= c.name

Polymorphic has-many-through accepts_nested_attributes_for error

I have a problem with my following setup. It is a polymorphic n:m association between the feature, page and slide model. the join model is the slideshow model.
feature.rb - a model in a refinerycms extension
module Refinery
module MyExtension
class Feature < Refinery::Core::BaseModel
# associations
has_many :slideshows, :as => :slideable, :class_name => "::Refinery::MyExtension::Slideshow"
has_many :slides, :through => :slideshows, :class_name => "::Refinery::MyExtension::Slide"
accepts_nested_attributes_for :slides, :allow_destroy => :false
end
end
end
page_decorator.rb - a decorator for the refinery page model
Refinery::Page.class_eval do
# associations
has_many :slideshows, :as => :slideable, :class_name => "Refinery::MyExtension::Slideshow"
has_many :slides, :through => :slideshows, :class_name => "Refinery::MyExtension::Slideshow"
end
slide.rb - a model in a refinerycms extension
module Refinery
module MyExtension
class Slide < Refinery::Core::BaseModel
# associations
has_many :slideshows, :class_name => "::Refinery::MyExtension::Slideshow"
has_many :pages, :through => :slideshows, :source => :slideable, :source_type => "::Refinery::Page"
has_many :features, :through => :slideshows, :source => :slideable, :source_type => "::Refinery::MyExtension::Feature"
end
end
end
slideshow.rb - a model in a refinerycms extension
module Refinery
module MyExtension
class Slideshow < Refinery::Core::BaseModel
# associations
belongs_to :slide, :class_name => "::Refinery::MyExtension::Slide"
belongs_to :slideable, :polymorphic => true
accepts_nested_attributes_for :slide, :allow_destroy => :false
end
end
end
I think the associations are correct, but I have a problem creating new slides within the feature#form.
feature-form:
<%= form_for [refinery, :my_extension_admin, #feature] do |f| -%>
<%= f.text_field :field1 %>
<%= f.text_field :field2 %>
<%= "some-more-fields..." %>
<% slideshows = #feature.slideshows.empty? ? #feature.slideshows.build : #feature.slideshows %>
<%= f.fields_for(:slideshows, slideshows) do |slideshow_form| %>
<%= slideshow_form.hidden_field :position, :value => 0 %>
<% slide = slideshow_form.object.slide.nil? ? slideshow_form.object.build_slide : slideshow_form.object.slide %>
<%= slideshow_form.fields_for(:slide, slide) do |slide_form| %>
<%= slide_form.text_field :a_field -%>
<%= slide_form.text_field :another_field -%>
<% end %>
<% end %>
<% end %>
If I hit "save" I get following error:
::Refinery::MyExtension::Slideshow(#70206105711540) expected, got Array(#70206014033940)
My params hash looks as following:
{"utf8"=>"✓", "authenticity_token"=>"my-token", "switch_locale"=>"de", "feature"=>{"field1"=>"a value", "field2"=>"some value", "slideshows"=>{"position"=>"0", "slide_attributes"=>{"a_field"=>"some value", "another_field"=>"some value"}}}, "action"=>"create", "controller"=>"refinery/my_extension/admin/features", "locale"=>:de}
My controller looks as following:
module Refinery
module MyExtension
module Admin
class FeaturesController < ::Refinery::AdminController
crudify :'refinery/my_extension/feature', :title_attribute => 'name', :xhr_paging => true
def feature_params
params.require(:feature).permit(:field1, :field2, :slideshows => [:position, :slide => [:a_field, :anothter_field]])
end
end
end
end
end
I use Rails 4.1.5 and refinerycms. But I think it has nothing to do with refinerycms, just with normal Rails behavior.
I already took a look at following resources:
ActiveRecord::AssociationTypeMismatch when attempting to save nested attributes in Rails
Has Many Through Association Polymorphic Error
accepts_nested_attributes_for with has_many => :through Options
Anybody an idea what I am missing?
try to create method "new" something like this
def new
#feature = ::Refinery::MyExtension::Feature.new
#feature.slideshows.build
end
and edit method
def edit
#feature = ::Refinery::MyExtension::Feature.find(params[:id])
#feature.slideshows.build
end

Rails comments gem Acts_as_commentable on pins

I have a rails app where users can upload pins, I want to use the [acts_as_commentable_gem][1] to allow users to comment pins, here is my config:
app/models/pin.rb
class Pin < ActiveRecord::Base
acts_as_commentable
end
app/controlers/pins_controller.rb
def show
#pin.find params[:id]
#comment = #pin.comments.new
end
app/views/pins/show.html.erb
<%= form_tag "/pins/add_new_comment" do %>
<%= hidden_field_tag "id", post.id %>
<%= text_area_tag "comment[comment]" %>
<%= submit_tag "Pin Comment" %>
<% end %>
app/models/comment.rb
class Comment < ActiveRecord::Base
include ActsAsCommentable::Comment
belongs_to :commentable, :polymorphic => true
default_scope -> { order('created_at ASC') }
# NOTE: install the acts_as_votable plugin if you
# want user to vote on the quality of comments.
#acts_as_voteable
# NOTE: Comments belong to a user
belongs_to :user
end
app/controllers/pin_controller.rb
def add_new_comment
pin = Pin.find(params[:id])
pin.comments << Pin.new(params[:comment])
redirect_to :action => :show, :id => pin
end
finally in my config/routes
get "/pins/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins", :via => [:pin]
But I run to a routing error:
undefined local variable or method `acts_as_commentable' for PinsController:Class
I am really not sure where this error come from, any ideas?
I am not really sure but you route shouldn't be like
get "/pins/:id/add_new_comment" => "pins#add_new_comment", :as => "add_new_comment_to_pins"

Nested attributes using paperclip rails 4

I am new to rails and I am trying to work with nested attributes.
The main idea is to have a a deal(offer) model, a deal will have multiple deal_photos from paperclip.
I have already watched Ryan's Railscast for nested forms and read many articles with many tips regarding problems on the same issue but still it doesn't work for me.
Here is my Implementation:
class Deal < ActiveRecord::Base
belongs_to :user
has_many :deal_photos, dependent: :destroy
accepts_nested_attributes_for :deal_photos
end
class DealPhoto < ActiveRecord::Base
belongs_to :deal
has_attached_file :photo, :styles => { :large => "600x170", :medium => "250x250!", :thumb => "100x100>" }, :default_url => lambda { |photo| photo.instance.set_default_url}
def set_default_url
ActionController::Base.helpers.asset_path('missing.png')
end
end
In my deals controller:
class DealsController < ApplicationController
def new_deal
#deal=Deal.new()
#user= User.find(params[:id])
3.times { #deal.deal_photos.build }
end
def create
#deal = Deal.new(deal_param)
#user= User.find(params[:user_id])
if #deal.save
#user.deals << #deal
flash[:notice]="Thank you"
end
end
def edit
#deal=Deal.find(params[:deal_id])
3.times { #deal.deal_photos.build }
end
def update
#deal=Deal.find(params[:id])
if #deal.update_attributes(deal_params)
flash[:notice]="Deal updated successfully"
end
end
private
def deal_params
params.require(:deal).permit(:title, :description, :contact_num, :user_id, :deal_photos_attributes => [ :id, :caption, :photo, :deal_id])
end
Finally in my form for a new deal:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
<label>Title<b style="color:red;">*</b>
<%= f.text_field(:title, :placeholder=>"") %>
</label>
------------more fields---------------------
<%= f.fields_for :deal_photos do |builder| %>
<div>
<%= builder.label :caption, "Image Caption" %>
<%= builder.text_field :caption %>
<%= builder.label :photo, "Image File" %>
<%= builder.file_field :photo %>
</div>
<%end%>
<%= button_tag("Create", :class=> "secondary button", :button_type => "submit") %>
(I have migrated the db for deals_photo to accept paperclip)
The above, creates a form with all fields but instead of 3 inputs for file upload shows only one. It creates 3 empty associations #deal.deal_photos but even if I choose one image to upload from the form it doesn't save it.
If you have any useful advices or another similar question please help!
What's in your deal_param method?
Do you permit deal_photos' attributes in it?
If no then do something like
def deal_params
params.require(:deal).permit(deal_attr1, deal_attr2,...., deal_photos_attributes: [:deal_photo_attr1, ...])
end
Also, do you get a deal_id in your deal_photos in view?
Finally, I was able to solve the problem in the new_deal.html.erb when I replaced the:
<%= form_for(:deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
with
<%= form_for(#deal, :url=>{:action=>'create', :user_id=> #user.id}) do |f| %>
What is changed is that the second line is for the specific new deal instance. Maybe the reason that the first was not working is that the deal_photos didn't get the deal_id, as Alexphys said. But still I haven't figure out the exact reason.