I have a problem : when a customer enters his shipping and billing informations in my form, the fields of the address model lose all information if the page is reloaded.
It works with the other fields, like email, that are included directly in the order model. How could I leave the fields filled after reloading ?
Here's my new.html.erb file :
<%= form_for #order do |f| %>
<ul>
<% #order.errors.each_with_index do |msg, i| %>
<li><%= msg[1] %></li>
<% end %>
</ul>
<%= f.text_field :email, placeholder: "email" %>
<%= f.fields_for :shipping_address_attributes do |sa| %>
<%= sa.text_field :first_name, placeholder: "Firstname" %>
<%= sa.text_field :last_name, placeholder: "Name", autocomplete: true %>
<%= sa.text_field :address1, placeholder: "Address", autocomplete: true %>
#etc.
<% end %>
<p><%= f.submit 'Next step' %></p>
<% end %>
My models :
class Order < ActiveRecord::Base
belongs_to :billing_address, :class_name => "Address"
belongs_to :shipping_address, :class_name => "Address"
accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address, reject_if: :bill_to_shipping_address
class Address < ActiveRecord::Base
belongs_to :user
has_many :billing_addresses, :class_name => "Order", :foreign_key => "billing_address_id", dependent: :nullify
has_many :shipping_addresses, :class_name => "Order", :foreign_key => "shipping_address_id", dependent: :nullify
validates_presence_of :first_name, :last_name, :address1, :city, :country, :phone, :postal
and my order_controller.rb:
def new
#user = current_user
#order_items = current_order.order_items
#order = current_order
#amount = #order.subtotal
end
def update
#order_items = current_order.order_items
#order = current_order
if #order.update(order_params)
redirect_to recapitulatif_de_la_commande_path
else
redirect_to(:back)
end
end
EDIT
Maybe the error is due to the fact that the order is not linked to any shipping address before the update action ? It works only if address model validate the presence of each attributes.
Any idea ?
Related
I am trying to create a nested form which has options and suboptions, both from the same model called Option. Here is the content of the files:
Model:
class Option < ApplicationRecord
belongs_to :activity
has_many :option_students
has_many :students, through: :option_students
has_many :suboptions,
class_name: "Option",
foreign_key: "option_id"
belongs_to :parent,
class_name: "Option",
optional: true,
foreign_key: "option_id"
accepts_nested_attributes_for :suboptions,
reject_if: ->(attrs) { attrs['name'].blank? }
validates :name, presence: true
end
Controller:
class OptionsController < ApplicationController
include StrongParamsHolder
def index
#options = Option.where(option_id: nil)
end
def show
#option = Option.find(params[:id])
end
def new
#option = Option.new()
1.times { #option.suboptions.build}
end
def create
#option = Option.new(option_params)
if #option.save
redirect_to options_path
else
render :new
end
end
def edit
#option = Option.find(params[:id])
end
def update
#option = Option.find(params[:id])
if #option.update_attributes(option_params)
redirect_to options_path(#option.id)
else
render :edit
end
end
def destroy
#option = Option.find(params[:id])
#option.destroy
redirect_to options_path
end
end
_form.html.erb:
<%= form_for #option do |f| %>
<p>
<%= f.label :name %><br>
<%= f.text_field :name %><br>
<%= f.label :activity %><br>
<%= select_tag "option[activity_id]", options_for_select(activity_array) %><br>
</p>
<div>
<div id="suboptions">
<%= f.fields_for :suboptions do |suboption| %>
<%= render 'suboption_fields', f: suboption %>
<% end %>
<div class="links">
<%= link_to_add_association 'add suboption', f, :suboptions %>
</div>
</div>
</div>
<p>
<%= f.submit "Send" %>
</p>
<% end %>
_suboption_fields.html.erb
<div class="nested-fields">
<%= f.label :suboption %><br>
<%= f.text_field :name %>
<%= link_to_remove_association "X", f %>
</div>
StrongParamsHolder:
def option_params
params.require(:option).permit(:name, :activity_id, :students_ids => [], suboptions_attributes: [:id, :name])
end
The view is created correctly, but it is not saving. It goes to "render :new" on create controller. I think it should be a problem with the params, but I am not sure what.
Probably not saving because of a failed validation. If you are using rails 5, the belongs_to is now more strict, and to be able to save nested-params you need to make the connection/relation between association explicit.
So imho it will work if you add the inverse_of to your relations as follows:
has_many :suboptions,
class_name: "Option",
foreign_key: "option_id",
inverse_of: :parent
belongs_to :parent,
class_name: "Option",
optional: true,
foreign_key: "option_id"
inverse_of: :suboptions
If another validation is failing, it could also help to list the errors in your form (e.g. something like #option.errors.full_messages.inspect would help :)
As an aside: I would rename the option_id field in the database to parent_id as this more clearly conveys its meaning.
In my app users has many companies, and companies has many users, companies has many divisions and users have different division in different company for example User with id 1 belongs to Company 1 and Division 2 and to Company 2 Division 3
User.rb
class User < ActiveRecord::Base
has_many :companies, through: :users_companies
has_many :users_companies
has_many :divisions, through: :users_divisions
has_many :users_divisions
has_many :users_roles, dependent: :destroy
has_many :roles, through: :users_roles
end
Company.rb
class Company < ActiveRecord::Base
#before_create :create_division
has_many :users_companies
has_many :users, through: :users_companies
has_many :divisions, dependent: :destroy
has_many :positions
end
Division.rb
class Division < ActiveRecord::Base
has_ancestry
belongs_to :company
has_many :users, through: :users_divisions
has_many :users_divisions
end
UsersCompany.rb
class UsersCompany < ActiveRecord::Base
belongs_to :user
belongs_to :company
end
UsersDivision.rb
class UsersDivision < ActiveRecord::Base
belongs_to :user
belongs_to :division
belongs_to :company
end
UsersDivision table have structure
id|user_id|division_id|company_id
when create all be fine
UsersDivision.create!(user: #user, division_id: params[:user][:division_ids], company_id: #company.id)
but when I try to update #user in table UsersDivision column company_id will be nill.
def update
#company = Company.find(params[:company_id])
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to :back
end
end
How to pass params :company_id to update action?
<div class="edit-registration-container">
<%= #user.full_name %>
<%= form_for([#company, #user]) do |f| %>
<%= f.label :last_name, "Фамилия" %><br />
<%= f.text_field :last_name, type: "text" %>
<%= f.label :first_name, "Имя" %><br />
<%= f.text_field :first_name, type: "text" %>
<%= f.label :middle_name, "Отчество" %><br />
<%= f.text_field :middle_name, type: "text" %>
<%= f.label :division_ids, "Подразделение" %><br />
<%= f.select :division_ids, #divisions_select %><br />
<%= f.hidden_field :company_id, value: #company.id %>
<%= f.fields_for :positions, #position do |ff| %>
<%= ff.label :name, "Должность" %>
<%= ff.text_field :name, type: "text" %>
<%= ff.hidden_field :company_id, value: #company.id %>
<% end %>
<%= hidden_field_tag "user[role_ids][]", nil %>
<% Role.all.each do |role| %>
<%= check_box_tag "user[role_ids][]", role.id, #user.role_ids.include?(role.id), id: dom_id(role) %>
<%= label_tag dom_id(role), role.name %><br>
<% end %>
<%= f.submit "Сохранить", class: "login loginmodal-submit", type: "submit" %>
<% end %>
</div>
You need to permit that parameter to be accessible, so add it in your
user controller params permit:
params.require(:user).permit(YOUR PARAMETERS, {:company_id => []})
Then you can call it using:
params["user"]["company_id"]
I think you can simply do this inside your update action:
#company = Company.find(params["user"]["company_id"])
Here is my working example form:
<%= form_for :user, :url => custom_users_path do |f| %>
<%= f.text_field :name %>
<%= f.hidden_field :company_id, :value => Company.find(1).id %> #4
<%= f.submit "Submit" %>
After I submit, inside my custom action my params["user"]["company_id"] would have this value: 4
I'm using rails 3.2.14 and having trouble using has_many :through for the first time. I'm using a has_many :through relationship between Image and Design tables using a Design_Pictures table that will store the order ranking for design images. All Images are associated with one User. Later I want the flexibility to store other images in the Images table that are not associated with a particular design.
I can successfully add sample data to my database and show the image title (which is stored in the images table) and ranking (which is stored in the design_pictures table) in my show design pages. What I can't figure out is how to create a new design_picture. Once I can get this working I'm going to use CarrierWave or Paperclip to add images to the Image table.
Here are my models:
app/models/image.rb:
class Image < ActiveRecord::Base
attr_accessible :title
belongs_to :user
has_many :design_pictures, dependent: :destroy
has_many :designs, :through => :design_pictures
validates :user_id, presence: true
validates :title, length: { maximum: 80 }
end
app/models/design.rb:
class Design < ActiveRecord::Base
attr_accessible :title
has_many :design_pictures, dependent: :destroy
has_many :images, :through => :design_pictures
validates :title, presence: true, length: { maximum: 60 }
end
app/models/design_picture.rb:
class DesignPicture < ActiveRecord::Base
attr_accessible :ranking
belongs_to :image
belongs_to :design
validates :image_id, presence: true
validates :design_id, presence: true
default_scope order: 'design_pictures.ranking ASC'
end
app/models/user.rb:
class User < ActiveRecord::Base
attr_accessible :name
has_many :designs, dependent: :destroy
has_many :images, dependent: :destroy
validates :name, presence: true, length: { maximum: 50 }
end
Views:
app/views/designs/show.html.erb:
<div>
<% if #design.design_pictures.any? %>
<h3>Images (<%= #design.design_pictures.count %>)</h3>
<ul>
<%= render #design_pictures %>
</ul>
<% end %>
</div>
<div>
<%= render 'shared/design_picture_form' %>
</div>
app/views/design_pictures/_design_picture.html.erb
<li>
<%= design_picture.image.title %> - Ranking: <%= design_picture.ranking %>
</li>
app/views/shared/_design_picture_form.html.erb:
<%= form_for(#design_picture) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :title, "Title" %>
<%= f.text_field :title,
placeholder: "Name your image.",
class: "" %>
<%= f.label :ranking, "Ranking" %>
<%= f.text_field :ranking,
placeholder: "Rank your design picture.",
class: "" %>
<%= hidden_field_tag(:design_id, #design.id) %>
<%= f.submit "Add Image", class: "btn btn-large btn-primary" %>
<% end %>
Controllers:
app/controllers/designs_controller.rb
def show
#design = Design.find(params[:id])
#design_pictures = #design.design_pictures.find(:all, :limit => 10)
#image = current_user.images.build
#design_picture = #design.design_pictures.build
end
app/controllers/design_pictures_controller.rb
def create
#current_design = Design.find(params[:design_id])
#image = current_user.images.new(params[:title])
#design_picture = #current_design.design_pictures.build(:image_id => #image.id, params[:ranking])
if #design_picture.save
flash[:success] = "Micropost created!"
redirect_to #current_design
else
redirect_to designs_url
end
end
Error when I visit the design_picture form partial:
undefined method `title' for #<DesignPicture image_id: nil, design_id: 1427, ranking: nil>
If I remove the title from the form I can submit form but nothing is created.
Any help would be greatly appreciated.
Your DesignPicture does not have a title attribute. When you do:
#design.design_pictures.build
It build a new DesignPicture instance. And the following do not work:
<%= form_for(#design_picture) do |f| %>
# ...
<%= f.label :title, "Title" %>
# ...
You might want to take a look at Nested Form
I'm not sure if this is the best way to go about this but this is how I was able to get my form to submit and create both an Image entry with it's title attribute and the Design_Picture entry with it's rank attribute. I ended up not needing to use accepts_nested_attributes_for.
app/views/shared/_design_picture_form.html.erb
<%= form_for(#design_picture) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= label_tag(:title, "Title") %>
<%= text_field_tag(:title) %>
<%= f.label :ranking, "Ranking" %>
<%= f.text_field :ranking,
placeholder: "Rank your design picture.",
class: "" %>
<%= hidden_field_tag(:design_id, #design.id) %>
<%= f.submit "Add Image", class: "btn btn-large btn-primary" %>
app/controllers/designs_controller.rb
def show
#design = Design.find(params[:id])
#design_pictures = #design.design_pictures.find(:all, :limit => 10)
#design_picture = #design.design_pictures.build
end
app/controllers/design_pictures_controller.rb
def create
#image = current_user.images.create(:title => params[:title])
#current_design = Design.find(params[:design_id])
#design_picture = #current_design.design_pictures.build(params[:design_picture])
#design_picture.image_id = #image.id
if #design_picture.save
flash[:success] = "Design Picture created!"
redirect_to #current_design
else
redirect_to designs_url
end
end
I have four controllers - users, categories, stories and comments. My problem is with comments. When I submit a comment #comment.save is false and I can't understand where is the problem. My table in DB for Comment has content, user_id, story_id. Here is part of my code:
def new
#comment = Comment.new
#story = Story.find(params[:story_id])
end
def create
#story = Story.find(params[:story_id])
if current_user
#comment = current_user.comments.create(params[:comment])
end
if #comment.save
flash[:success] = "Successfull added comment"
redirect_to story_path(#story)
else
render 'new'
end
end
show.html.erb for StoriesController:
<b><%= #story.title %></b> <br/><br/>
<%= #story.content %> <br/><br/>
<% #story.comments.each do |comment| %>
<b>Comment:</b>
<%= comment.content %>
<% end %>
<%= form_for([#story, #story.comments.build]) do |f| %>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Add" %>
</div>
<% end %>
comment.rb:
class Comment < ActiveRecord::Base
attr_accessible :content, :story_id, :user_id
belongs_to :story
belongs_to :user
validates :content, :presence => true
validates :story_id, :presence => true
validates :user_id, :presence => true
default_scope :order => 'comments.created_at DESC'
end
story.rb
class Story < ActiveRecord::Base
attr_accessible :title, :content, :category_id
belongs_to :user
belongs_to :category
has_many :comments
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
default_scope :order => 'stories.created_at DESC'
end
UPDATE
When I use save! I have an error message Story cannot be blank.
You need to set the story for the comment your are building since (as you've obviously worked out), the story in question is given by params[:story_id]. That story id isn't magically going to find its way into the params[:comment] hash. You could either do
#comment = #story.comments.build(params[:comment])
#comment.user = current_user
or create the comment on the user and then set its story.
I am new to rails and using a combination of formtastic, activeadmin,sti and polymorphic associations to build a form
When I I can create a nested form with the address parent with no problem, but when i introduce STI and attempt to build_origin_address instead of build_address, that is when I get the error below when loading the edit view
NameError in Admin/leads#edit
Showing .../app/views/admin/leads/_form.erb where line #3 raised:
uninitialized constant Lead::OriginAddress
Models:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :lead
validates :line1, :presence => true, :length => {:minimum => 2}
attr_accessible :line1, :line2, :city, :state, :zip, :country
end
class OriginAddress < Address
end
class DestinationAddress < Address
end
class Lead < ActiveRecord::Base
has_one :origin_address, :dependent => :destroy, :as => :addressable
accepts_nested_attributes_for :origin_address, :allow_destroy => true
end
partial used in edit view:
<%= semantic_form_for [:admin, #lead] do |f| %>
<% #lead.build_origin_address unless #lead.origin_address %>
<%= f.inputs :name => "Lead Info" do %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<% end %>
<%= f.semantic_fields_for :origin_address do |origin| %>
<%= origin.inputs :name => "Origin Address" do %>
<%= origin.input :line1 %>
....
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
I think you must define #lead before your form.