i want to use 'reform' gem to create object with nested attribute. i have models:
class Dish < ActiveRecord::Base
belongs_to :lunch_set
end
class Side < ActiveRecord::Base
belongs_to :lunch_set
end
class LunchSet < ActiveRecord::Base
belongs_to :restaurant
belongs_to :day
has_one :dish
has_many :sides
end
lunchset controller 'new' method:
def new
#lunch_set = #restaurant.lunch_sets.build
#form = LunchSetForm.new(dish: Dish.new, side: Side.new)
respond_to do |format|
format.html # new.html.erb
format.json { render json: #lunch_set }
end
end
routes file:
namespace :admin do
resources :restaurants do
resources :lunch_sets
resources :days do
resources :lunch_sets
end
end
end
and LunchSetForm
class LunchSetForm < Reform:Form
include DSL
include Reform::Form::ActiveRecord
property :name, on: :dish
property :name, on: :side
end
my question is how to construct views/admin/lunch_sets/_form.html , especially considering those routes? when i tried
= simple_form_for #form do |f|
= f.input :name
= f.input :name
.actions
= f.submit "Save"
but it gives me error
undefined method `first' for nil:NilClass
and points into line
= simple_form_for #form do |f|
form_for (and in turn, simple_form_for) expect the form object to have ActiveModel methods like model_name to figure out how to name your form and its inputs and to resolve the form's action url. You're close to getting it right by including Reform::Form::ActiveRecord, but there are a couple more things you need to do:
require 'reform/rails'
class LunchSetForm < Reform:Form
include DSL
include Reform::Form::ActiveRecord
property :name, on: :dish
property :name, on: :side
model :dish
end
The model :dish line tells Reform that you want the form's 'main model' to be the Dish instance. This means that it will make your form respond to the methods that ActiveModel usually provides for normal Rails models using the 'main model' to provide the values for those methods. Your form input names will look like dish[name] etc and it will post to your dishes_url. You can set your model to anything you like, but an instance whatever you choose needs to be passed into the form constructor.
Related
I'm getting this error when I try to mass-assign a HABTM relationship in Rails 5:
*** ActiveRecord::RecordNotFound Exception: Couldn't find Job with ID=6 for Profile with ID=
class Profile < ApplicationRecord
has_and_belongs_to_many :jobs
accepts_nested_attributes_for :jobs
end
class Job < ApplicationRecord
has_and_belongs_to_many :profiles
end
class ProfilesController < ApplicationController
def create
#profile = Profile.new(profile_params)
end
private
def profile_params
params.require(:profile).permit(
:name,
:email,
:jobs_attributes: [:id]
)
end
end
=form_for #profile do |f|
=f.fields_for :jobs do |j|
=j.select :id, options_for_select([[1, "Job 1", ...]])
The problem is that accepts_nested_attributes_for is a way to update attributes on an associated object (either already linked or one that you're creating). You can think of it doing something like:
params[:jobs_attributes].each do |job_attributes|
#profile.jobs.find(job_attributes[:id]).attributes = job_attributes
end
Except that the job is then saved with the new attributes in an after-save of the parent object.
This isn't what you want. In fact, you don't need accepts_nested_attributes at all.
Instead, change the attribute in your view to job_ids as if it's an attribute of the profile, something like the following:
=form_for #profile do |f|
=j.select :job_ids, options_for_select([[1, "Job 1", ...]])
This will effectively call profile.job_ids = [1,2,3] which will have the effect that you're looking for.
In order to have a coherent experience, I need to create a form which splits fields for an associated model. For a has_one association it works perfectly, however for a has_many, things go south.
class Book < ApplicationRecord
has_many :pages
acceptes_nested_attributes_for :pages
end
--
class Page < ApplicationRecord
belongs_to :book
end
--
class BooksController < ApplicationController
def new
#book = Book.new
#page = #book.pages.build
end
end
--
new.html.slim
= form_for #book do |f|
# normal book fields
= fields_for :pages, #page do |p|
p.text_field :title
p.number_field :title_size
# some more book fields
HERE'S THE CATCH. I need to add some more fields for THE SAME PAGE
= fields_for :pages, #page do |p|
p.text_area :body
p.number_field :page_number
The thing is, when I send the form, in my strong params I get as many indices as fields_for I write.
ActionController::Parameters{... "pages_attributes" => "0" => {"title"=> "","title_size"=> ""}, "1" => { "body"=> "", "page_number"=> "" } }
0 and 1 in Actioncontroller::Parameters correspond to each fields_for I place, even though I am specifically using the record_object attribute with #page. I need all of those fields_for to correspond to the same instance.
What am I doing wrong? I'm out of options now. Thanks in advance!
I'm actually creating a taxonomy system into my application. Here is my tables schema :
Taxonomies
class CreateTaxonomies < ActiveRecord::Migration
def change
create_table :taxonomies do |t|
t.references :taxonomable, polymorphic: true
t.integer :term_id
end
end
end
Terms
class CreateTerms < ActiveRecord::Migration
def change
create_table :terms do |t|
t.string :name
t.string :type
t.integer :parent_id, default: 0
end
end
end
and here are my associations :
class Taxonomy < ActiveRecord::Base
belongs_to :taxonomable, polymorphic: true
end
class Term < ActiveRecord::Base
self.inheritance_column = :_type_disabled // because I use type as table field
has_many :taxonomies, as: :taxonomable
end
To make it more generic, I create a concern :
module Taxonomable
extend ActiveSupport::Concern
included do
has_many :taxonomies, as: :taxonomable
end
def get_associate_terms
terms = self.taxonomies.map { |t| t.term_id }
taxonomies = Term.find terms
end
end
and I'm including it into my model :
class Post < ActiveRecord::Base
include Taxonomable
end
It works fine and I can retreive the associated data using get_associate_terms. My problem is located within my controller and my form. I'm actually saving it like that :
# posts/_form.html.haml
= f.select :taxonomy_ids, #categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'
# PostsController
def create
#post = current_user.posts.new( post_params )
if #post.save
#post.taxonomies.create( term_id: params[:post][:taxonomy_ids] )
redirect_to posts_path
else
render :new
end
end
This create method is saving the data correctly but if you take a look at the params attribute, you will see that the object taxonomies is waiting for a term_id but I can only use taxonomy_ids in my form. It feels kind of dirty and I wanted to have your point of view to avoid hacking around like that.
Also, and I think this problem is linked with the one above, when editing my item, the select box is not checked the actual matching category associate to the current post.
Any thoughts are welcome.
Thanks a lot
EDIT :
Here is my form
= form_for #post, url: posts_path, html: { multipart: true } do |f|
= f.select :taxonomy_ids, #categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'
EDIT 2 :
I added the accepts_nested_attributes_for to my concern as it :
module Taxonomable
include do
has_many :taxonomies, as: :taxonomable, dependent: :destroy
accepts_nested_attributes_for :taxonomies
end
end
and then used fields_for in my form :
= f.fields_for :taxonomies_attributes do |taxo|
= taxo.label :term_id, 'Categories'
= taxo.select :term_id, #categories.map { |c| [c.name, c.id] }, {}, class: 'form-control'
When submitting the form, I receive it :
"post"=>{"type"=>"blog", "taxonomies_attributes"=>{"term_id"=>"2"}, "reference"=>"TGKHLKJ-567TYGJGK", "name"=>"My super post"
However, when the post has been saved with success, the associations are not. Any ideas???
EDIT 3 :
In my controller, I added this :
def post_params
params.require(:post).permit(
taxonomies_attributes: [:term_id]
)
end
When submitting the form, I've got the following error :
no implicit conversion of Symbol into Integer
According to that post Rails 4 nested form - no implicit conversion of Symbol into Integer, it's because I'm using taxonomies_attributes in my fields_for as:
= f.fields_for :taxonomies_attributes do |taxo|
However, if I remove it to :
= f.fields_for :taxonomies do |taxo|
The block is displaying nothing except the div wrapping it :
<div class="form-group">
<!-- Should be display here but nothing -->
</div>
EDIT 4 :
Finally make it works. The fact that the select box was not showing came from the fact that when creating a new resource, my #post has no taxonomies. Doing the following fix that :
def new
#product = current_user.products.new
category = #product.taxonomies.build
end
thanks to everyone
I am not sure if I completely understand your question, but one thing I noticed is that you don't really need to save in two steps.
Just add the following line to your Taxonomable module (Rails 3)
attr_accessible :taxonomies_attributes
accepts_nested_attributes_for :taxonomies
If you are using Rails 4, add only the accepts_nested_attributes_for to your Taxonomable module and each of the Controllers, make sure to allow taxonomies attributes. For example, in your PostsController, add the following to your
def post_params
params.require(:post).permit(:name, taxonomies_attributes: [:name])
end
Your create will change to:
def create
#post = current_user.posts.new( post_params )
if #post.save
redirect_to posts_path
else
render :new
end
end
This is assuming that your form uses the proper nesting via fields_for - I am not sure about that since you didn't post the form code.
I'm trying to build a form_for to create a join model between two other models. I have a Book model and User model, with another called Reads that is my join. Here is how I've set up the associations:
class User < ActiveRecord::Base
has_many :reads
has_many :books, :through => :reads
end
class Book < ActiveRecord::Base
has_many :reads
has_many :users, :through => :reads
end
class Read < ActiveRecord::Base
belongs_to :book
belongs_to :user
end
I've looked at the docs for form_for and watched the railscast episode on many-to-many associations, but I can't figure out why I'm getting the error when I try to render the Book#show view where I've put the form:
First argument in form cannot contain nil or be empty
Here is my form in app/views/books/show.html.erb:
<%= form_for(#read) do |f| %>
<%= f.hidden_field :book_id, value: #book.id %>
<%= button_to 'Add to Reads', {controller: 'reads', action: 'create'}, {class: 'btn'} %>
<% end %>
I think part of the problem is that I am trying to create a 'Reads' object from the Books model, but I'm not sure what I am doing wrong. I need the 'Add to Reads' button on the Book's page so that a user can select that particular book to add to their 'reads.' I'm also adding the current_user id in the controller, rather than in the view. Here is my create action from the Reads controller if that helps...
def create
#read = Read.new(read_params)
#read.user_id = current_user.id
#read.save
if #read.save
# do this
else
# do that
end
end
And I'm using strong params...
def read_params
params.require(:read).permit(:user_id, :book_id)
end
Thanks for any help.
First argument in form cannot contain nil or be empty
This means that #read in your form is nil. Since you are in the show action of your Books controller, you have to define this variable in the books controller.
def show
#read = Read.new
...
end
I have a question on rails3 nested_form.
These are my two models:
class User
belongs_to :shop
accepts_nested_attributes_for :shop
end
class Shop
has_many :users
end
In my register view(i am using Devise):
form_for(resourse,:url => registration(resource_name)) do |f|
=f.fields_for :shop do |s|
=s.text_fields :name
but i get nothing for this form. What should i do?
You need to add some objects first to it. Use build method on model in controller.
Example:
#shop = Shop.new
3.times { #shop.users.build }
More informations at Railscasts. AJAX is used in second part of this video.