Polymorphic has-many-through accepts_nested_attributes_for error - ruby-on-rails-4

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

Related

rails: param.require(:model) ActionController::ParameterMissing OR Empty

My goal is to create a new Reminder record with hardcoded values:
In the following structure:
Reminder belongs_to :deck
Deck has_one :reminder, dependent: :destroy
In deck controller I get to the view like this :
def repitition_alerts
#deck = Deck.find(params[:id])
#reminder = Reminder.new
end
On that page I want to create a new Reminder with a link_to:
<%= link_to "make alerts", deck_reminders_path(#deck, #reminder, {:action => :create}, next_alert: 'soon', interval: false), :method => :post %>
I am getting the following error in the browser:
ActionController::ParameterMissing in RemindersController#create
From terminal output:
ActionController::ParameterMissing (param is missing or the value is empty: reminder):
app/controllers/reminders_controller.rb:34:in `reminder_params'
app/controllers/reminders_controller.rb:19:in `create'
In the reminders_controller.rb I have:
def reminder_params
params.require(:reminder).permit(:deck_id, :interval, :next_alert, :alerts)
end
If I understand it correctly. Rails don't see the #reminder passed into it? But it's in the page. I can put this on the same page <%= #reminder %> and I see #<Reminder:0x007fc012fa00a8> rendered out on the page. So the object itself exists.
(Rails 4.2)
You need the params for reminder nested under :reminder. Switch your link_to to this:
<%= link_to "make alerts", deck_reminders_path(
#deck,
#reminder,
{:action => :create},
reminder: {
next_alert: 'soon',
interval: false
}
), :method => :post %>

Rails 4 has_many through: nested model id field is not inserted

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?

Kaminari paginate at different controller mixing with devise (check answer)

I have 2 non nested models, User and Record. The goal is to paginate the #user.records called #records at users/show
Here is the Record part:
at app/models/record.rb
class Record < ActiveRecord::Base
default_scope lambda { order('records.created_at DESC') }
paginates_per 48
end
I am using Kaminari at records/index and works great. Problem is to use it at users/show
Here the app/controllers/users_controller.rb
def show
#user = User.find(params[:id])
#records = #user.records.page params([:page])
# Not working alternative:
# #records = #user.records.page(params[:page]).per(48)
end
Here is the view that triggers the display, is the listing rendered inside users/show...
<% #records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<%= paginate #records %>
Errors are very interesting. As it is, error is:
No route matches {:action=>"show", :controller=>"users", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
Meaning paginate #records is building a request to Active Record that hopes to find an action I do not have in that controller (I am using devise). So at Kaminari instructions says is possible to pass the params, like this:
<%= paginate #records, :params => { :controller => 'foo', :action => 'bar' }, :remote => true %>
Then the error becomes like this:
No route matches {:action=>"remote_records_pagination", :controller=>"records", :controllers=>{"registrations"=>:registrations}, :id=>"1", :page=>nil}
I have a remote_recors_pagination defined at records_controller, renders records_paginate_remotely.js, but the pagination method does not find it. Why it keeps showing :controllers registrations?
Finally, to change the view like this:
<%= paginate #user.records %>
<% #user.records.each do |record| %>
<%= link_to (image_tag record.thumbnail.url(:list)), record %>
<%= link_to record.name, record %>
<% end %>
<% end %>
Produces an undefined method error.
Should not the example be working with or without js file? Any help?
Thanks.
I found a solution. I am posting an answer because the problem was on routes and the mix with devise, common combo that more people may find.
So, routes was like this:
devise_for :users
resources :users, only: :show, , :controllers => { :registrations => :registrations } do
member do
get :following, :followers
end
end
To change it to this:
devise_for :users, :controllers => { :registrations => :registrations }
resources :users, only: :show do
member do
get :following, :followers
end
end
allows the paginate command interact with Active Record normally. Devise first test seems ok.

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.