I'm trying to set up a polymorphic association for photo uploads which are processed using Carrierwave. I'm using Simple Form to build my forms. I feel like the association is correct so I'm wondering if my problem is just something with the form or controller.
Here are my associations:
property.rb:
class Property < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
...
end
unit.rb
class Unit < ActiveRecord::Base
attr_accessible :image
...
has_many :image, :as => :attachable
end
image.rb
class Image < ActiveRecord::Base
belongs_to :attachable, :polymorphic => true
mount_uploader :image, PhotoUploader
end
properties_controller.rb:
def edit
#property = Property.find params[:id]
#property.image.build if #property.image.empty?
end
def update
#property = Property.find params[:id]
if #property.update_attributes params[:property]
redirect_to admin_properties_path, :notice => 'The property has been successfully updated.'
else
render "edit"
end
end
Snippet from properties/_form.html.erb
<%= f.input :image, :label => 'Image:', :as => :file %>
Here is the error I get when submitting with an image attached:
undefined method `each' for #<ActionDispatch::Http::UploadedFile:0x00000102291bb8>
And here are the params:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"lvB7EMdc7juip3gBZD3XhCLyiv1Vwq/hIFdb6f1MtIA=",
"property"=>{"name"=>"Delaware Woods",
"address"=>"",
"city"=>"",
"state"=>"",
"postal_code"=>"",
"description"=>"2 bedroom with large kitchen. Garage available",
"incentives"=>"",
"active"=>"1",
"feature_ids"=>[""],
"user_ids"=>[""],
"image"=>#<ActionDispatch::Http::UploadedFile:0x00000102291bb8 #original_filename="wallpaper-4331.jpg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"property[image]\"; filename=\"wallpaper-4331.jpg\"\r\nContent-Type: image/jpeg\r\n",
#tempfile=#<File:/tmp/RackMultipart20120608-3102-13f3pyv>>},
"commit"=>"Update Property",
"id"=>"18"}
I'm looking everywhere for help on polymorphic associations and am getting nowhere. I've seen simple examples that look pretty straight forward. One thing I've noticed is that it seems like in a lot of the examples the has_many association in my case should be images and not image. However when I do that I get an error:
Can't mass-assign protected attributes: image
I've tried updating my form to use fields_for as I've seen in other blogs like so:
<%= f.input :image, :label => "Photo", :as => :file %>
<% f.simple_fields_for :images do |images_form| %>
<%= images_form.input :id, :as => :hidden %>
<%= images_form.input :attachable_id, :as => :hidden %>
<%= images_form.input :attachable_type, :as => :hidden %>
<%= images_form.input :image, :as => :file %>
<% end %>
All I know is I'm having a heck of a time getting this to work. I'm pretty new to Rails so even debugging it is difficult. It doesn't help that the debugger doesn't really work in 3.2 :(
Since your models have_many :images (it should be :images, not :image), you'll want to use nested_forms in your views. You should set up accepts_nested_attributes_for :images on the unit and property models and change the attr_accessible from :image to :image_attributes.
Check out http://railscasts.com/episodes/196-nested-model-form-part-1 for a good guide on getting going with it.
Related
I came back to the relatively "old book" Head First rails, which was published for Rails 2.3.
Now, going back again through those samples and using Rails 3 I came up with some questions.
Let's say that I'm adapting the sample for coconut airways and instead of flights and seats, I have a project and tasks.
The page shows a project description and below a list of tasks associated to that project. so far so good. now below that there is a form to create new task. This task needs a Task object and the project_id. here is when things do not work as before.
if you want to do it like the old style you will type:
<%= render :partial => "new_task",
:locals => {:task => Task.new(#project.id)} %>
well, this is showing the mass-assign error.
Then I tried to pass both as parameter:
<%= render :partial => "new_task",
:locals => {:task => Task.new, :project_id => #project.id} %>
and assign it in the partial
<%= f.hidden_field :project_id, :value => project_id %>
any hint?
EDITED:
class Task < ActiveRecord::Base
belongs_to :project
attr_accessible :title
end
class Project < ActiveRecord::Base
has_many :tasks
attr_accessible :description, :title
end
If you change your model's attr_accessible you can include these assignments to be made. For more information about attr_accessible and mass assignment see: Ruby on Rails API
I've been getting the UnkownAttributeError for no particular reason, my models seem to be setup correctly...
School.rb
class School < ActiveRecord::Base
attr_protected :id, :created_at, :updated_at
#relationships
has_many :users
accepts_nested_attributes_for :users
end
My School model used to have the following, but it produced a MassAssignmentSecurity error for the user fields:
attr_accessible :country, :name, :state_or_province, :users_attributes
User.rb
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :instructor_id, :first_name, :last_name, :school_id
#relationships
belongs_to :school
end
new.html.haml
= simple_form_for #school do |f|
.well
= f.input :name, :as => :hidden
= f.input :country, :as => :hidden
= f.input :state_or_province, :as => :hidden
.well
= f.simple_fields_for #school.users.build do |user_form|
= user_form.input :first_name, :required => true
= user_form.input :last_name, :required => true
= user_form.input :username, :required => true
...
= f.button :submit, "Next"
Note: #school is being populated in my new action from session information gathered on the previous page, I'm making a multi-step form. The school data is perfectly valid, if I was to remove the user form it would have no trouble saving the school.
The specific error message I'm getting in my create action:
ActiveRecord::UnknownAttributeError in SchoolsController#create
unknown attribute: user
And the sent params looks a little like this:
{"school"=>{"name"=>"Elmwood Elementary", "country"=>"38",
"state_or_province"=>"448", "user"=>{"first_name"=>"joe",
"last_name"=>"asdas", "username"=>"asasdads",
"email"=>"asdasd#sdas.ca", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}}, "commit"=>"Next"}
Is this maybe a bug with either Devise or simple_form? I'm using Rails 3.2.3
Ok, so apparently I needed to provide the symbol :users - the name of the relationship as my first argument for it to work.
I have the following structure working on my application.
class Foo < ActiveRecord::Base
has_many :examples, :dependent => :destroy
accepts_nested_attributes_for :examples
end
class Example < ActiveRecord::Base
belongs_to :foo
has_many :codes, :dependent => :destroy
accepts_nested_attributes_for :codes, :reject_if => lambda { |a| a[:code].blank? }
end
class Code < ActiveRecord::Base
belongs_to :example
has_many :code_kinds
has_many :kinds, :through => :code_kinds
attr_reader :kind_tokens
def kind_tokens=(ids)
self.kind_ids = ids.split(",")
end
end
class CodeKind < ActiveRecord::Base
belongs_to :code
belongs_to :kind
end
class Kind < ActiveRecord::Base
has_many :code_kinds
has_many :codes, :through => :code_kinds
end
And it's working perfectly for the form with fields_for on create and save.
I'm using kind_tokens as described on RailsCast #258 Token Fields
But on the edit form everything displays perfectly now I should be pre-populating the data in a data-pre attribute on the kind_tokens field inside the nested attributes for code in examples.
The RailsCast say:
<%= f.text_field :author_tokens, "data-pre" => #book.authors.map(&:attributes).to_json %>
But I can't do #foo.examples.codes.kinds.map... because the relation with Foo and examples returns a collection, the same situation with codes.
I'm just using:
<%= f.fields_for :codes do |codes_form| %>
That's inside of
<%= f.fields_for :examples do |examples_form| %>
Now how can I pre-populate the kind for code if I don't have any loop, and everything's done by nested_attributes and fields_for ?
Solved
Everytime you use a
<%= f.fields_for ...
Rails automatically makes a loop so you can have some kind of counter there like:
<%
#ctrEx = 0
#ctrCd = 0
%>
<%= form_for #foo ...
<%= f.fields_for :examples do |examples_form| %>
...
<%= examples_form.fields_for :codes do |codes_form| %>
...
<%= codes_form.text_field :kind_tokens, :class => "tag_matcher", "data-pre" => #foo.examples[#ctrEx].codes[#ctrCd].kinds.map(&:attributes).to_json %>
...
<%#ctrCd +=1%>
<%end%>
...
<%
#ctrEx += 1
#ctrCd = 0
%>
<%end%>
<%end%>
Now you can use your counters in the data-pre like this:
#foo.examples[#ctrEx].codes[#ctrCd].kinds.map(&:attributes).to_json
That's the way i figured it out, but there must be another way.
I'm using ActiveAdmin (0.4.0) with Rails (3.1.1).
I can't find a nice way/hack to handle multiple nested resources.
Considerer 3 models as:
class Program < ActiveRecord::Base
has_many :knowledges, :dependent => :destroy
end
class Knowledge < ActiveRecord::Base
belongs_to :program
has_many :steps, :dependent => :destroy
end
class Step < ActiveRecord::Base
belongs_to :knowledge
end
And the ActiveAdmin resources:
ActiveAdmin.register Program do
end
ActiveAdmin.register Knowledge do
belongs_to :program
end
ActiveAdmin.register Step do
belongs_to :knowledge
end
In routes.rb:
namespace :admin do
resources :programs do
resources :knowledges do
resources :steps
end
end
end
Here's the urls for the index of the programs, the knowledges and the steps :
http://localhost:3000/admin/programs
http://localhost:3000/admin/programs/1/knowledges
http://localhost:3000/admin/programs/1/knowledges/1/steps
No problem for the "Knowledge" admin but the "Step" admin don't keep the nested context.
For example, when I use filters in steps#index I'm redirected to:
http://localhost:3000/admin/knowledges/1/steps?params...
But it must have been:
http://localhost:3000/admin/programs/1/knowledges/1/steps?params...
Same problem when I create a new resource:
http://localhost:3000/admin/knowledges/1/steps/new
Instead of:
http://localhost:3000/admin/programs/1/knowledges/1/steps/new
Same problem with the breadcrumb... etc...
What I've tried so far in app/admin/steps.rb:
ActiveAdmin.register Step do
belongs_to :knowledge
config.clear_action_items!
action_item :only => :index do
link_to('Create Step', new_admin_program_knowledge_step_path(knowledge.program.id, knowledge.id))
end
index do
column :id
column :knowledge
column :title
column "Actions" do |step|
link_to("Voir", admin_program_knowledge_step_path(step.knowledge.program, step.knowledge, step), :class => "member_link show_link") +\
link_to("Editer", edit_admin_program_knowledge_step_path(step.knowledge.program, step.knowledge, step), :class => "edit_knowledge member_link edit_link", :id => "knowledge_#{dom_id(knowledge)}") +\
link_to("Supprimer", admin_program_knowledge_step_path(step.knowledge.program, step.knowledge, step), :class => "member_link delete_link", :method => :delete, :confirm => "Delete?")
end
end
filter :id
filter :title
filter :subtitle
filter :stage_type
filter :order_by
filter :created_at
filter :updated_at
form :partial => "form"
end
And in app/views/admin/steps/_form.html.erb I must use the activeadmin formbuilder:
<%= semantic_form_for(resource, :url => admin_program_knowledge_steps_path(resource.knowledge.program, resource.knowledge), :builder => ActiveAdmin::FormBuilder) do |f|
f.inputs "Step" do
f.input :knowledge, :as => :hidden
f.form_buffers.last << f.template.content_tag(:li, f.template.content_tag(:label, "Knowledge")+f.template.content_tag(:p, f.object.knowledge.title))
f.input :title
f.input :order_by
end
f.buttons
end %>
Well... I'm stuck.
How to handle this nicely? Any clues appreciated...
Well, the solution is pretty simple...
https://github.com/josevalim/inherited_resources
ActiveAdmin.register Step do
controller do
nested_belongs_to :program, :knowledge
end
end
I have following two models
class Office < ActiveRecord::Base
has_many :locations, :dependent => :destroy
end
class Location < ActiveRecord::Base
belongs_to :office
end
I have a new.html.erb for the office model and the below code in OfficeController
def create
#office = Office.new(params[:deal])
if #office.save
redirect_to office_url, :notice => "Successfully created office."
else
render :action => 'new'
end
end
How can I add fields for Location model in new.html.erb of Office?
I want to be able to have fields for locations in the same form.
You'll have to use nested attributes to do this. Fortunately, Rails makes it pretty easy. Here's how to do it:
First, signify to Office that you're giving it Location fields as well by adding this line:
accepts_nested_attributes_for :location.
Now, in new.html.erb, add the fields that you want. Say we want to have city and state:
<%= f.fields_for :location do |ff| %>
<%= ff.label :city %>
<%= ff.text_field :city %>
<%= ff.label :state %>
<%= ff.text_field :state %>
<% end %>
That's it!