GithubHelp home page GithubHelp logo

Nested forms about padrino-docs HOT 5 OPEN

padrino avatar padrino commented on June 3, 2024
Nested forms

from padrino-docs.

Comments (5)

ujifgc avatar ujifgc commented on June 3, 2024

From @dariocravero on September 9, 2014 16:32

@fgarcia I know it might be a bit confusing and that probably the whole form builders section needs to be redone. I'll get started using your example here :).

First of all, the form builder helpers expect the symbol you use to be either an instance variable available to the view or an object it can instantiate on the fly.

Having said that, you can still force the name of the field by using the as: :model in fields_for as in: fields_for :model, as: :model.

Here's a sample app that should work with it:

# app/app.rb
module Issue1760
  class App < Padrino::Application
    register Padrino::Helpers
    enable :sessions

    get :index do
      render :index
    end
  end
end

# app/views/index.slim
= form_for :model, '/some/specific/path' do |f|
  = f.label :email
  = f.text_field :email

#models/model.rb
class Model
end

It should render:

<form action="/form/posted" accept-charset="UTF-8" method="post">
  <label for="model_email" value="">Email: </label>
  <input type="text" name="model[email]" value="" id="model_email">
</form>

Notice how I've merged the usage of form_tag and fields_for in form_for.

Now, let's jump into nested models/data structures. The issue you're facing there is that you're trying to use an association that doesn't exist or isn't explicitly declared. The helper is only trying to access model.inside and inside is undefined for your current model object. Let's extend the app above to support associations:

# app/views/index.slim
= form_for :model, '/some/specific/path' do |f|
  = f.label :email
  = f.text_field :email

  = f.fields_for :inside do |fi|
    = fi.label :name
    = fi.text_field :name

# models/model.rb
class Model
  def inside
    Inside.new
  end
end

# models/inside.rb
class Inside
end

That would render something like:

<form action="/form/posted" accept-charset="UTF-8" method="post">
  <label for="model_email" value="">Email: </label>
  <input type="text" name="model[email]" value="" id="model_email">
  <label for="model_inside_attributes_name" value="">Name: </label>
  <input type="text" name="model[inside_attributes][name]" value="" id="model_inside_attributes_name">
</form>

That would be the case of a one to one association in a relational db. If you were to return an array of elements, it would then render as many as you return. So, say we modify `models/model.rb to look like this:

# models/model.rb
class Model
  def inside
    [Inside.new, Inside.new]
  end
end

It should output:

<form action="/form/posted" accept-charset="UTF-8" method="post">
  <label for="model_email" value="">Email: </label>
  <input type="text" name="model[email]" value="" id="model_email">
  <label for="model_inside_attributes_0_name" value="">Name: </label>
  <input type="text" name="model[inside_attributes][0][name]" value="" id="model_inside_attributes_0_name">
  <label for="model_inside_attributes_1_name" value="">Name: </label>
  <input type="text" name="model[inside_attributes][1][name]" value="" id="model_inside_attributes_1_name">
</form>

If we were to add an ORM like, say Sequel, and name the models Parent and Child with a one parent to many children relationship, we would end up with something along the lines of:

# app/views/index.slim
= form_for :parent, url(:parents, :index) do |f|
  = f.label :email
  = f.text_field :email

  = f.fields_for :children do |fi|
    = fi.label :name
    = fi.text_field :name

  = f.submit

# app/controllers.rb
Issue1760::App.controllers :parents do
  get :new do
    @parent = Parent.new
    @parent.children << Child.new
    render :index
  end

  get :view, with: :id do
    @parent = Parent[params[:id]]
    render :index
  end

  post :index do
    parent = Parent.create(email: params['parent']['email'])

    params['parent']['children_attributes'].each do |i, child_data|
      Child.create(parent_id: parent.id, name: child_data['name'])
    end

    redirect url(:parents, :view, parent.id)
  end
end

# models/parent.rb
class Parent < Sequel::Model
  one_to_many :children
end

# models/child.rb
class Child < Sequel::Model
  many_to_one :parent
end

And that's kind of how the whole relations thing would go when you layered up to using ORM models together with the form builder.

Hope this helped clarify things a bit and if not, let me know and we'll look at it in more depth. Here's the demo app.

:)

from padrino-docs.

ujifgc avatar ujifgc commented on June 3, 2024

From @dariocravero on September 9, 2014 16:32

@padrino/core-members should we update the guides with something along the lines of this?

from padrino-docs.

ujifgc avatar ujifgc commented on June 3, 2024

From @fgarcia on September 9, 2014 17:0

That was more exhaustive than I expected! Thanks a lot

I downloaded your example, played with it and verified one thing... when you mentioned instantiate on the fly we made different assumptions. Somewhere in the doc I also read that and thought about instantiate without a model

Your example uses form_for which I thought could achieve the result I wanted using a real model. Now it is so much clear!

However in my example I used form_tag because I wanted to use the helpers without an existing model. My assumption was that the helpers behaved like in Rails. I've just tested this quickly in Rails:

<%= form_tag do %>
    Form contents
    <%= text_field_tag(:outside) %>
    <%= fields_for :model do |f| %>
      <%= f.text_field(:inside) %>
      <%= f.fields_for :again do |ff| %>
        <%= ff.text_field(:deeper) %>
      <% end %>
    <% end %>
<% end %>

The last line is rendered as:

<input id="model_again_deeper" name="model[again][deeper]" type="text">

That was my expectation when combining fields_for with form_tag

It is my fault misunderstanding since I assumed that if fields_for could be used within form_tag an no prefixed model, then I expected that no model at all was required :-(

thanks for the lesson!

from padrino-docs.

ujifgc avatar ujifgc commented on June 3, 2024

From @dariocravero on September 9, 2014 17:31

I get your pain point and I agree that it should probably work without an explicit model too, e.g., what if you need to create a form for a service you don't manage in the same app but you know the structure of? Perhaps we could try to mimic that behaviour @padrino/core-members thoughts?

from padrino-docs.

ujifgc avatar ujifgc commented on June 3, 2024

From @halfdan on November 6, 2015 11:54

It'd also be great if it would allow to render an "Add" button that adds additional nested elements on the fly (in the DOM, using javascript).

from padrino-docs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.