I have a class MatriculaForm with some associations (belongs_to and has_many):
class MatriculaForm < Reform::Form
property :aluno, form: PessoaForm
properties :atributos_extras, :mensalidade
#validation
validates :aluno, :dia_vencimento, :empresa, presence: true
end
And the _form.html.erb
<%= form_for #matricula_form do |f| %>
<%= f.fields_for :aluno do |aluno| %>
<%= aluno.text_field :nome %>
<% end %>
<% end %>
On controller, I do
MatriculaForm.new(params[:matricula])
But the initialize reform method raise a error:
NoMethodError (undefined method `aluno' for #<ActionController::Parameters:0x007fe835772a70>
I saw that the parameters become with aluno_attributes key name. But reading the docs, thoses parameters names are accepeted.
I am doing something wrong?
Did you try to whitelist the attributes for association?
association_attributes: [:id .... etc.]
When the method error appears it might be that the association is not correct? Did you correctly set up the belongs_to and has_many
Does this only happen while validating? Does the form save without validation? I am not sure whether the validation can be done that way. May be you want to use validates_association
Please check the docs for correct syntax.
Related
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've googling and trying everything I could think of for the past couple of days to solve a relatively simple (I presume) issue with has_and_belongs_to_many relation.
I managed to successful use the HABTM relation to submit a single relation value. Here's the sample code:
Model:
class Livre < ActiveRecord::Base
has_and_belongs_to_many : auteurs
end
class Auteur < ActiveRecord::Base
has_and_belongs_to_many :livres
end
Controller:
def new
#livre = Livre.new
#auteurs = Auteur.all
end
def create
#livre = Livre.new(livre_params)
if #livre.save
redirect_to [:admin, #livre]
else
render 'new'
end
end
private
def livre_params
params.require(:livre).permit(:name, :auteur_ids)
end
View:
<% f.label :auteur %><br>
<% f.collection_select(:auteur_ids, #auteurs, :id, :name) %>
Posted Params:
{"utf8"=>"✓",
"authenticity_token"=>"mAXUm7MRDgJgCH00VPb9bpgC+y/iOfxBjXSazcthWYs=",
"livre"=>{"name"=>"sdfsdfd",
"auteur_ids"=>"3"},
"commit"=>"Create Livre"}
But when I try to add "multiple true" to the view's collection_select helper, the (now multiple) relation doesn't get saved anymore. Sample code:
(both Model and Controller unchanged)
View:
<% f.label :auteur %><br>
<% f.collection_select(:auteur_ids, #auteurs, :id, :name, {}, {:multiple => true}) %>
Posted Params:
{"utf8"=>"✓",
"authenticity_token"=>"mAXUm7MRDgJgCH00VPb9bpgC+y/iOfxBjXSazcthWYs=",
"livre"=>{"name"=>"sdfsdf",
"auteur_ids"=>["1",
"5",
"3"]},
"commit"=>"Create Livre"}
As you can see, the params for "auteur_ids" is now an array. That's the only difference.
What am I doing wrong?
Just to clarify: both piece of code are able to add a new record to the livres db table, but only the 1st code is able to add the appropriate record to the auteurs_livres db table. The second one simply does not insert anything into auteurs_livres.
(I run on ruby 1.9.3p194 and rails 4.0.1)
Thanks!
Answer
For the fine folks stuck with the same problem, here's the answer:
Edit your controller and change the permitted parameter from :auteur_ids to {:auteur_ids => []}
params.require(:livre).permit(:name, {:auteur_ids => []})
And it now works :)
For the fine folks stuck with the same problem, here's the answer:
Edit your controller and change the permitted parameter from :auteur_ids to {:auteur_ids => []}
params.require(:livre).permit(:name, {:auteur_ids => []})
And it now works :)
You worked out the solution because Rails now expects auteur_ids to be an array, rather than a single item. This means that instead of just passing a single entity to the model, it will package the params as [0][1][2] etc, which is how you can submit your HABTM records now
There is a more Rails way to do this, which is to use accepts_nested_attributes_for. This is going to seem like a lot more work, but it will dry up your system, and also ensure convention over configuration:
Model
class Livre < ActiveRecord::Base
has_and_belongs_to_many : auteurs
accepts_nested_attributes_for :auteurs
end
class Auteur < ActiveRecord::Base
has_and_belongs_to_many :livres
end
Controller
def new
#livre = Livre.new
#livre.auteurs.build
#auteurs = Auteur.all
end
def create
#livre = Livre.new(livre_params)
if #livre.save
redirect_to [:admin, #livre]
else
render 'new'
end
end
private
def livre_params
params.require(:livre).permit(:name, auteur_attributes: [:auteur_id])
end
Form
<%= form_for #livre do |f| %>
<%= f.text_field :your_current_vars %>
<%= f.fields_for :auteurs do |a| %>
<%= a.collection_select(:auteur_id, #auteurs, :id, :name, {}) %>
<% end %>
<% end %>
This will submit the auteur_id for you (and automatically associate the livre_id foreign key in the HABTM model. Currently, this will only submit the number of objects which have been built in the new action -- so in order to add more items, you'll have to build more
On my payments page there are certain variables such as card_number that I want to pass from the View to the Model but I do not want to store them in the db. I can usually easily achieve this by simply using attr_accessor but in this case the model is being passed in params through accepts_nested_attributes_for and for some reason the params are not being passed through:
in User.rb i have
has_many :credit_cards
accepts_nested_attributes_for :credit_cards
in the view file i have a nested form field, something like:
blah blah
<h2>Credit card</h2>
<%= f.fields_for :credit_cards do |builder| %>
<%= render "credit_card_fields", :f => builder %>
<% end %>
inside that
<p>
<%= f.label :test %><br />
<%= f.text_field :test %>
</p>
now back in credit_card.rb i have:
attr_accessor :test
before_create :show_me_test_param
private
def show_me_test_param
raise "#{test}"
end
Now the strange thing is that when I try to save a record, it simply returns an empty exception. The param does not seem to have been passed through from User to CreditCard through accepts_nested_attributes_for?
The param being passed in is:
{"email"=>"name#example.com", "password"=>"pass123", "password_confirmation"=>"pass123", "credit_cards_attributes"=>{"0"=>{"test"=>"helllo this is the second attempt", "name_on_card"=>"first lastname", "card_number"=>"987498742897", "card_verification_value"=>"232", "expiry_date"=>"2141"}}}
Does anyone know whats going on? Does accepts_nested_attributes_for work with attr_accessor?
This has messed me up several times in the past! Params for nested objects come to the controller with the key model_name_attributes which gets passed to the new or update_attributes method of the model in the controller.
So you'll need to add :credit_card_attributes to your attr_accessor to allow that key to be passed in.
I have a model with a corresponding form, for which I use ActiveRecord validations. At the bottom of the form I'd like to have a single confirmation checkbox which should not be persisted, but which must be checked for the form to be submitted. I'd also like any errors that stems from this checkbox not being checked to display alongside the ActiveRecord errors.
Now I could cobble something together in the controller manually, but I'm wondering if there is a built-in, cleaner way to handle this kind of situation?
I think you should add this in your model:
validates_acceptance_of :check_me
attr_accessor :check_me
attr_accessible :check_me # if you already have attr_accessible defined in your model
and this in your view:
<%= form_for #your_model do |f| %>
# some code
<%= f.check_box :check_me %>
<% end %>