L
L
Lesha Fedoseev2014-01-31 20:18:51
JavaScript
Lesha Fedoseev, 2014-01-31 20:18:51

Generating (render) form editing nested object via ajax (with jquery-fileupload-rails)?

I have 2 models:

  1. building →has_many :building_views
  2. buildingview →belongs_to :building

I can only create a BuildingView for an existing Building (via edit/update Building). BuildingView attributes: image ( image) and title ( title).
Images are uploaded via Carrierwave.

Estimated workflow:
  1. The user enters the Building edit page
  2. There is a file_field that allows you to upload multiple files at once
  3. It selects the files and they are loaded using the gem jquery-fileupload-rails(creating a BuildingView for each image)
  4. Immediately after loading, they appear on the current page (via ajax, without reloading): preview and field for editing the BuildingView title

With points 1, 2 and 3 everything is ok. Pictures are loaded, BuildingViews are created, and after reloading the page, they appear on the editing page of the corresponding Building with a preview and a title editing field (which is also successfully edited).

Problem with point number 4: it is not possible to display the BuildingView edit form via ajax. I can't figure out how to render the corresponding nested form partial. Here are my files:

controllers/admin/buildings_controller.rb
# other defs ...

def edit
  @building = Building.find(params[:id])
end

def update
  @building = Building.find(params[:id])
    if @building.update_attributes(building_params)
      flash[:success] = 'Woohoo!'
      redirect_to admin_buildings_url
    else
      render :edit
    end
end

# other defs ...

private
  def building_params
    params.require(:building).permit(:all_building_params,
                                      building_views_attributes: [
                                        :_destroy,
                                        :id,
                                        :building_id,
                                        :image,
                                        :title
                                      ])
  end


views/admin/buildings/edit.html.haml
%h1 Edit building
= form_for [:admin, @building] do |f|
  = render 'admin/buildings/form', f: f
  .form-element-container
    .form-element.b-form-labels  
    .form-element.b-form-fields
      = f.submit 'Edit building'
      = link_to t('admin.cancel'), :back

= form_for [:admin, BuildingView.new] do |f_bv|
  = f_bv.hidden_field :building_id, value: @building.id
  = f_bv.file_field :image, multiple: true, name: 'building_view[image]'


views/admin/buildings/_form.html.haml
// fields for Building...

#building_views
  .form-element-container
    .form-element
      %h2 Building views

= f.fields_for :building_views do |bv_form|
  = render 'admin/buildings/form_building_views', f: bv_form


views/admin/buildings/_form_building_views.html.haml
.form-element-container
  .form-element.b-form-labels Image:
  .form-element.b-form-fields= image_tag(f.object.image_url(:thumb)) if f.object.image

.form-element-container
  .form-element.b-form-labels Title:
  .form-element.b-form-fields= f.text_field :title


assets/javascript/admin/buildings.js.coffee
jQuery ->
  $('#building_view_image').fileupload(
    dataType: 'script'
  )


controllers/admin/building_views_controller.rb
class Admin::BuildingViewsController < ApplicationController

  def create
    @building_view = BuildingView.create(building_view_params)
  end

  private

    def building_view_params
      params.require(:building_view).permit(:building_id, :image)
    end

end


views/admin/building_views/create.js.haml
- if @building_view.new_record?
  == alert('Oops!');
- else
  == $('#building_views').append('#{j render('admin/buildings/form_building_views')}');


When sending files, I see an error in the console:
ActionView::Template::Error (undefined local variable or method `f' for #<#<Class:0x007ffaa52faad8>:0x007ffaa7393970>):


I need to pass this one f:
j render( partial: 'admin/buildings/form_building_views', locals: { f: ??? } )


How can I do this for a nested form partial?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
L
Lesha Fedoseev, 2014-02-01
@alexfedoseev

In general, without understanding how I can ftransfer this to this partial (as far as I can judge it and not transfer it), I decided to go by recreating this partial “by hand”.
Firstly, I created a separate partial for ajax insertion (I immediately give the result, below I explain where the variable @buildingand helper appeared in it building_nested_model_count):

.form-element-container
  .form-element.b-form-labels= image_tag(@building_view.image_url(:thumb)) if @building_view

  .form-element.b-form-fields= text_field_tag "building[building_views_attributes][#{building_nested_model_count(@building_view, @building)}][title]", nil, placeholder: 'Title'

= hidden_field_tag "building[building_views_attributes][#{building_nested_model_count(@building_view, @building)}][id]", @building_view.id

In it, I simply recreated the form that I need to add via ajax (rails generates it automatically using helpers, and I generated it manually). In order for it to work, I need to make changes to three files:
1. Define the variable @building
class Admin::BuildingViewsController < ApplicationController

  def create
    @building_view = BuildingView.create(building_view_params)
    @building = @building_view.building # определяем @building
  end

  private

    def building_view_params
      params.require(:building_view).permit(:building_id, :image)
    end

end

2. There is an index for the hash paramsin the fields idand nameforms for each BuildingView (see the ajax partial), let's calculate it using the helper:
module Admin::BuildingsHelper

  def building_nested_model_count(nested_var, building)
    nested_class = nested_var.class
    nested_class.where(building_id: building.id).count
  end

end

3. Finally, change the render partial:
- if @building_view.new_record?
  == alert('Oops!');
- else
  == $('#building_views').append('#{j render('admin/buildings/form_building_views_ajax')}');

Due to my little experience, I don’t understand: is this a crutch or a solution to the problem (I’ll listen to opinions with pleasure). But it works: the form for the new BuildingView is rendered, its edited one is titlesaved.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question