When I use form_for :model the data is saved when I submit the form.
However when I use form_tag, the data is lost after the form is processed.
I need to use form_tag because I have two models in one form.
Is there a way to save form data with form_tag?
You are making two incorrect assumptions in your question. First, form_tag is not necessary or even recommended for multiple-model forms; Second, form_tag doesn't do anything fundamentally different from form_for, you are most likely not formatting the field names correctly for your controller.
In order to create a form with nested models, you need to use the fields_for helper in conjunction with form_for. The relationship needs to be defined first in the model with accepts_nested_attributes_for. Since you have not given us any information about your models, I will give you a made-up example:
class Person < ActiveRecord::Base
has_one :address
accepts_nested_attributes_for :address
end
class Address < ActiveRecord::Base
belongs_to :person
end
This tells ActiveRecord that the Person model can accept attributes for Address, and will pass along the attributes to the correct model to be created.
<% form_for :person do |p| %>
<% p.fields_for :address do |a| %>
use the a form builder to create
fields for the address model here
<% end %>
<% end %>
chaining the fields_for helper from the p form builder lets the helpers generate attributes in the correct format.
More information: Nested Model Forms
Pretty much the same way as before except you'll need to build the params. You can look at your log to see how params are being sent.
eg.
def create
#silly_hat = SillyHat.new( :name => params[:name], :size => params[:size], :colour => params[:colour] )
if #silly_hat.save
...
Related
This question is regarding Rails 4/postgresql and the app is hosted on Heroku.
I am making a Quiz-functionality on a website and I am wondering on how to implement the forms (using Formtastic) best to make this is easy as possible. I have three models:
Quiz (has_many :quiz_questions), e.g. "Test to see how awesome you are"
QuizQuestion(belongs_to :quiz, has_many :quiz_options). e.g. "1. Which is your favorite color")
QuizOption (belongs_to :quiz_question). e.g. "Blue"
I have set up the forms like this:
<%= semantic_form_for([:admin, #quiz], :url => admin_quiz_path(#quiz.id)) do |f| %>
<%= render 'form' , :f => f %>
<% end %>
where the form looks like this:
<%= f.inputs %>
<h3>Quiz questions</h3>
<%= f.semantic_fields_for :quiz_questions do |qq_f| %>
<%= qq_f.inputs %>
<h4>Quiz options</h4>
<%= qq_f.semantic_fields_for :quiz_options do |qqo_f| %>
<%= qqo_f.inputs %>
<% end %>
<% end %>
<%= f.actions do %>
<%= f.action :submit %>
or go <%= link_to 'back', admin_quizzes_path %>
<% end %>
It seems, however, not to be working the way I want. I expect to be able to see the fields of QuizQuestion and QuizOptions in this form (there are objects for those) but I don't.
More importantly is that I would like to be able to create a New QuizQuestion and subsequently QuizOption in this form. It doesn't necessarily have to be jQuery/ajax or anything but I would like to do it all from this form.
Basically, I would like my workflow to be like:
Create a Quiz and add values to it. Click Create.
Add QuizQuestion number one and add the values to it (like "name label"). Click Create.
Add QuizOption related to QuizQuestion number one, and its "name label". Click create.
Repeat for QuizQuestion/QuizOption until the Quiz is done.
How can I do this?
For your workflow you might have to add accept_nested_attributes_for for the nested resources, this way when creating an object object you can actually create nested children (as long as they fulfill all the validations). This way:
# A quiz :has_many :quiz_questions
#quiz = Quiz.create(...)
with a declaration like:
has_many :quiz_questions
accepts_nested_attributes_for :quiz_questions
in your Quiz model you'll actually be able to create QuizQuestion from the quiz model like:
# using the previously quiz model
quiz.quiz_questions.create(...)
Doing the same for the deeply nested associations will do have the same effect.
Perhaps the reason why you don't see any field on the form is because there is not nested object created. Let me explain. When you create a new Quiz object, in your quizs_controller (or whatever the inflection for quiz is...) you need a:
def new
quiz = Quiz.new()
end
and
def create
Quiz.new(quiz_params)
end
private
def quiz_params
# whitelisted parameters sent along with the form
params.require(:quiz).permit(...)
end
if you actually want to be able to see the fields in the form you'll have to use the build method and actually populate that new object with respective the nested resources.
Note that for this to work with the form you will have to whitelist in the quizzes_controller the right attributes. You can debug the params you receive once you send the new quiz formulary and check that everything is right.
TIP! if you don't want to worry about the JS when adding nested resources dynamically, I recommend you using the cocoon gem
is a little project and I try to associate patient model with consultations. one patient has_many :consultations, in my form I have:
<%= f.association :patient %>
I pass the id parameter from the patient to the action 'new' in this way:
<%= link_to new_consultum_path(:id => #patient.id) %>
And in the view I have:
How can I make that the f.association field take the correspondent patient_id automatically?
How can I be sure that the patient_id is the current patient?
If I want to hide this field is that ok if I put
instead of
Is a better way to do this?
And why in the view shows me # patient:0x007f4e7c32cbd0 ?
thanks for your help.
And why in the view shows me # patient:0x007f4e7c32cbd0
This is a Patient object.
It means you need to call an attribute of this object - EG #patient.name.
--
f.association field take the correspondent patient_id automatically
This might help:
It looks like Organization model doesn't have any of these fields: [
:to_label, :name, :title, :to_s ] so SimpleForm can't detect a default
label and value methods for collection. I think you should pass it
manually.
#app/models/patient.rb
class Patient < ActiveRecord::Base
def to_label
"#{name}"
end
end
Apparently, you need to have either title, name or to_label methods in your model in order for f.association to populate the data.
-
How can I be sure that the patient_id is the current patient?
If you're having to verify this, it suggests inconsistencies with your code's structure. If you need the patient_id to be set as the current patient, surely you could set it in the controller:
#app/controllers/consultations_controller.rb
class ConultationsController < ApplicationController
def create
#consultation = Constultation.new
#consultation.patient = current_patient
#consultation.save
end
end
I can provide more context if required.
You want to associate consultations to patients using fields_for, which is similar to form_for, but does not build the form tags.
It you start with your patient object, you can iterate through the consultation associations binding it to form fields as you go.
it would look something like this
<%= form_for #patient do |patient_form| %>
<% patient_form.text_field :any_attribute_on_patient %>
<% #patient.consultations.each do |consultation| %>
<%= patient_form.fields_for consultation do |consultation_fields| %>
<% consultation_fields.text_field :any_attribute_on_consulatation %>
<% end %>
<% end %>
<% end %>
Sorry, the code may not be exactly right.
Check out the docs for field_for here
You will also have to set accepts_nested_attributes_for consultations on patient. When you set accepts_nested_forms_for, Rails will automatically update the associated consultations object to the patient and save any edits you have made. You DEFINITELY want to use accepts_nested_attributes_for most nested form handling of this type.
I have a Post model that have a title and content attributes.
I want to make it possible to tweet when the user creates a post like this.
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_area :content %>
<%= f.check_box :with_tweet %> # Error
<%= f.text_field :tweet %> # Error
<% end %>
This code fails, because there are no with_tweet and tweet attributes for Post.
I don't think query strings are good idea situation like this.
How should I send a information that is not related a model?
Define them as virtual attributes:
class Post < ActiveRecord::Base
...
attr_accessor :with_tweet, :tweet
...
end
attr_accessor will provide a getter and a setter method for with_tweet and tweet which should then be accessible to you through the #post object.
Further to Vee's answer, let me explain why you'd need it:
Every attribute in a Rails model is the result of using a Ruby
getter & setter - meaning that your model's attributes are
essentially just parts of a Ruby object, built when your class is
initialized
The problem you have is Ruby on Rails does not build any other
attributes other than the ones in your DB, meaning if you wanted to
track extra data, you'll have to use virtual attributes to let
the class know to populate those not in the db
attr_accessor is used to define those extra attributes
I am making my own custom view that I need to make the process of creating associated models less painful for my users. I want to display all of the models associated pieces in-line, with controls to edit them. This is quite easy to roll my own for the basic fields, but I'd rather use a form_filtering_select partial for the inline model's associations, but I can't find any documentation to do this.
You can use Nested Form
Consider a User class which returns an array of Project instances from the projects reader method and responds to the projects_attributes= writer method:
class User
def projects
[#project1, #project2]
end
def projects_attributes=(attributes)
# Process the attributes hash
end
end
Note that the projects_attributes= writer method is in fact required for fields_for to correctly identify :projects as a collection, and the correct indices to be set in the form markup.
When projects is already an association on User you can use accepts_nested_attributes_for to define the writer method for you:
class User < ActiveRecord::Base
has_many :projects
accepts_nested_attributes_for :projects
end
This model can now be used with a nested fields_for. The block given to the nested fields_for call will be repeated for each instance in the collection:
<%= nested_form_for #user do |user_form| %>
...
<%= user_form.fields_for :projects do |project_fields| %>
<% if project_fields.object.active? %>
Name: <%= project_fields.text_field :name %>
<% end %>
<% end %>
...
<% end %>
Here goes the Reference for details.
There's a cool gem out there that does pretty much what you want. It's called Nested Form Fields. It allows you to edit records (along with their has_many associations) on a single page. The cool thing about it is that it even uses jQuery to dynamically add/remove form fields without a page reload. Checkout out the gems docs for proper usage. Hope that helps!
Based on following models
class Company < ActiveRecord::Base
has_and_belongs_to_many :origins
end
class Origin < ActiveRecord::Base
has_and_belongs_to_many :companies
end
I want to have in my companies/_form a collection of checkboxes representing all origins.
Don't know if the Company.new(params[:company]) in companies_controller#create can create the association between company and the selected origins?
I'm running rails 3.0.0, what is the best way to achieve that?
thanks for your insights
habtm isn't a popular choice these days, it's better to use has_many :through instead, with a proper join model in between. This will give you the method Company#origin_ids= which you can pass an array of origin ids to from your form, to set all the associated origins for #company. eg
<% current_origin_ids = #company.origin_ids %>
<% form_for #company do |f| %>
<label>Name:<%= f.text_field :name %></label>
<% Origin.all.each do |origin| %>
<label><%= origin.name %>
<%= check_box_tag "company[origin_ids][]", origin.id, current_origin_ids.include?(origin.id) %>
</label>
<% end %>
<% end %>
As an aside, using a proper join model, with corresponding controller, allows you to easily add/remove origins with AJAX, using create/delete calls to the join model's controller.
I have to agreed with #carpeliam a has_many :through should not be the default choice. A HABTM works fine and involves less code. It also does not restrict the use of ajax and does expose a origin_ids setter to which you can pass an array of ids. Therefore the screencast, whilst from 2007, still works with Rails 3. The other option if using simple_form is this:
= form.association :origins, :as => :check_boxes
Personally I'm not of the belief that has-many-through is always better, it really depends on your situation. Has-many-through is better if there is ANY possibility of your join model having attributes itself. It's more flexible to change. It removes the magic of some Rails conventions. If however you don't need has-many-through, then there's an old RailsCast for HABTM checkboxes that might come in handy.