I have a problem with simple_form's associations.
Here are the models "linked"
class Contact < ApplicationRecord
belongs_to :state
end
class State < ApplicationRecord
CATEGORIES = [ "not-contacted", "on-going", "called"]
has_many :contacts
validates :category, inclusion: { in: CATEGORIES }
end
I have also a State seed with the three states above.
I'm creating the new form for a contact.
Controller :
def new
#contact = Contact.new
#states = State.all
end
def create
#contact = Contact.new(contact_params)
if #contact.save
redirect_to contact_path(params[:id])
else
render :new
end
end
View:
<%= simple_form_for(#contact) do |f| %>
<%= f.input :last_name, label: 'Nom' %>
<%= f.input :first_name, label: 'Prénom' %>
<%= f.input :number, label: 'Téléphone' %>
<%= f.input :email, label: 'Mail' %>
<%= f.input :address, label: 'Adresse' %>
<%= f.association :state, collection: State.order(:category), prompt: "Choisir un état" %>
<%= f.input :grade, label: 'Note', collection:[1, 2, 3, 4, 5] %>
<%= f.submit 'Créer le contact', class:'btn-modifications' %>
<% end %>
But I have a collection not with a list of "on-going", "called", "not-contacted" but I have a list with this:
State:0x00007fcb3afcfca8
How can I display the list I want?
You need to change it to below
<%= f.association :state, collection: State.order(:category), label_method: :category, value_method: :id,prompt: "Choisir un état" %>
Related
I'm trying to create a form on my web app so a user with the correct permissions can add a new "Site" to the database. I have a database table called site with all the correct attributes on my local machine. When the submit button is clicked on the form, I get the following error. I tried using an attribute accessor, but it causes many of my previous tests to fail. Is there a way to solve this problem without using attribute accessor?
Error:
NoMethodError in Admin::AddSitesController#create
undefined method `write_from_user' for nil:NilClass
def create
site = Site.new(site_params) <-- highlighted in error message
authorize(site)
Model
class Site < ApplicationRecord
include ActiveModel::Model
self.table_name = "site"
validates :name, presence: true
validates :address, presence: true
validates :year_built, inclusion: {in: 1700..Date.today.year, message: "that year is fake"},
allow_nil: true
validates :number_of_floors, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
validates :total_floor_area, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
validates :number_of_units, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
validates :primary_use_type, presence: true
validates :number_of_bedrooms, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
validates :people_per_bedroom, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
validates :water_performance_goal, numericality: {only_integer: true, greater_than: 0}, allow_nil: true
belongs_to :organization
belongs_to :weather_station
has_many :site_users, dependent: :destroy
has_many :users, through: :site_users
enum primary_use_type: {
commerical: "Commercial",
residential: "Residential"
}
enum building_type: {
affordable: "Affordable",
market_rate: "Market Rate"
}
enum population_type: {
family: "Family",
elderly_disabled: "Elderly/Disabled",
mixed_other: "Mixed/Other"
}
enum construction_type: {
brick_block: "Brick/Block",
concrete_slab: "Concrete/Slab",
wood_steel: "Light Framed Wood/Steel",
timber_steel: "Heavy Framed Timber/Steel"
}
Controller
module Admin
class AddSitesController < ApplicationController
def new
#site = Site.new
authorize(#site)
end
def create
site = Site.new(site_params)
authorize(site)
if site.valid?
site.save
flash[:notice] = "good"
redirect_to admin_superusers_path
else
flash[:messages] = site.errors.full_messages
redirect_to admin_manage_sites_path
end
end
private
def site_params
params.require(:site).permit(
:organization_id,
:name,
:address,
:year_built,
:construction_type,
:number_of_floors,
:total_floor_area,
:number_of_units,
:weather_station_id,
:primary_use_type,
:building_type,
:population_type,
:number_of_bedrooms,
:people_per_bedroom,
:water_performance_goal,
:sro
)
end
end
end
Form
<%= form_with(
model: #site,
url: admin_add_sites_path,
) do |form| %>
<div class="pr-8">
<% if flash[:messages] %>
<ul class=“flash alert”>
<% flash[:messages].each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
<% end %>
<h2 class="heading-300 text-green-800 mt-3" >
<%= t(".site_info")%>
</h2>
<%= form.label(:organization_id, "Organization", class: "form-label") %>
<% options = options_from_collection_for_select(#organizations, :id, :name, form.object.organization_id) %>
<%= form.select :organization_id, options%>
<%= form.label(:name, "Site name", class: "form-label") %>
<%= form.text_field(:name, autocomplete: "off", autocapitalize: "on", class: "form-input") %>
<%= form.label(:address, class: "form-label") %>
<%= form.text_field(:address, autocomplete: "off", autocapitalize: "on", class: "form-input") %>
<%= form.label("Format: address, city, state, zip code", class: "form-detail text-sm") %>
<h2 class="heading-300 text-green-800 mt-5" >
<%= t(".site_details")%>
</h2>
<%= form.label(:year_built, class: "form-label") %>
<%= form.text_field(:year_built, autocomplete: "off", class: "form-input") %>
<%= form.label(:construction_type, class: "form-label") %>
<%= form.select(:construction_type, Site.construction_types.values, :include_blank => true) %>
<%= form.label(:number_of_floors, class: "form-label") %>
<%= form.text_field(:number_of_floors, autocomplete: "off", class: "form-input") %>
<%= form.label(:total_floor_area, class: "form-label") %>
<%= form.text_field(:total_floor_area, autocomplete: "off", class: "form-input") %>
<%= form.label("Units: sqaure feet", class: "form-detail text-sm") %>
<%= form.label(:number_of_units, class: "form-label") %>
<%= form.text_field(:number_of_units, autocomplete: "off", class: "form-input") %>
<%= form.label(:weather_station_id, "NOAA weather station", class: "form-label") %>
<% options = options_from_collection_for_select(#weather_stations, 'id', 'zip_code', form.object.weather_station_id) %>
<%= form.select :weather_station_id, options%>
<%= form.label(:primary_use_type, class: "form-label") %>
<%= form.select(:primary_use_type, Site.primary_use_types.values, :include_blank => true) %>
<div aria-expanded="false" class="form__drawer">
<div class="pl-8 pb-8 mt-5">
<h2 class="heading-300">
<%= "Residential Options" %>
</h2>
<%= form.label(:building_type, class: "form-label") %>
<%= form.select(:building_type, Site.building_types.values, :include_blank => true) %>
<%= form.label(:population_type, class: "form-label") %>
<%= form.select(:population_type, Site.population_types.values, :include_blank => true) %>
<%= form.label(:number_of_bedrooms, class: "form-label") %>
<%= form.text_field(:number_of_bedrooms, autocomplete: "off", class: "form-input") %>
<%= form.label(:people_per_bedroom, class: "form-label") %>
<%= form.text_field(:people_per_bedroom, class: "form-input") %>
<%= form.label(:water_performance_goal, class: "form-label") %>
<%= form.text_field(:water_performance_goal, autocomplete: "off", class: "form-input", value: 60) %>
<%= form.label("Gal/Bedroom/Day ", class: "form-detail text-sm") %>
<%= form.label(:sro, "SRO", class: "form-label") %>
<%= form.select(:sro, ["yes", "no"], :include_blank => true) %>
</div>
</div>
<div class="mt-2">
<%= form.submit "Add", class: "button-primary w-full" %>
</div>
</div>
<% end %>
Routes
namespace :admin do
get "/" => "dashboards#show"
resources :site_users, only: [:update, :destroy]
resources :superusers, only: [:index]
resources :manage_sites, only: [:index, :update, :destroy]
resources :superuser_invitations, only: [:create]
resources :add_sites, only: [:create, :new]
resources :organizations, only: [] do
resources :managers, only: [:index]
resources :manager_invitations, only: [:create]
end
resources :sites, only: [] do
resources :users, only: [:index]
resources :user_invitations, only: [:create]
end
end
Figured it out- just needed to remove
include ActiveModel::Model
from the Site model as it is already connected to the database through its table.
Just to clarify Rachel's answer, include ActiveModel::Model should only be used in a model that doesn't have a table in your database. Since your Site model is already connected to the database through self.table_name = "site", Ruby will start to throw errors when you are trying to access columns and values in your Site table.
I am trying to make a form for storing data hierarchy through the associations.
My structure of database is
meta
- ID (PK)
version
- meta_id (FK of meta)
- ID (PK)
- lang (FK from lang ...)
- ....
data
- ID (FK of version)
I need to store multiple language content under one ID.
Models are
class Meta < Sequel::Model(:link_meta)
one_to_many :version
end
class Version < Sequel::Model(:link_version)
one_to_one :meta, key: :meta_id
one_to_many :data, key: :id
one_to_one :lang, key: :lang
end
class Link < Sequel::Model(:link)
plugin :timestamps, :create => :created, :update => :updated
many_to_one :version, key: :id
end
And my form for creating input is.
<% form_for :links, url(:links, :create), :class => 'form-horizontal' do |f| %>
<%= partial 'links/form', :locals => { :f => f } %>
<% end %>
And this is my partial
<% f.fields_for :version, :class => 'form-horizontal' do |cz| %>
<%= cz.hidden_field :lang, :value => Lang.select(:id).where(:lang => "cz").map(:id) %>
<% cz.fields_for :data, :class => 'form-horizontal' do |link| %>
<% error = #links.errors.key?(:url) && #links.errors[:url].count > 0 %>
<fieldset class='control-group <%= error ? 'has-error' : ''%>'>
... form content
</fieldset>
<% end %>
<% f.fields_for :version, :class => 'form-horizontal' do |en| %>
<%= en.hidden_field :lang, :value => Lang.select(:id).where(:lang => "cz").map(:id) %>
<% en.fields_for :data, :class => 'form-horizontal' do |link| %>
<% error = #links.errors.key?(:url) && #links.errors[:url].count > 0 %>
<fieldset class='control-group <%= error ? 'has-error' : ''%>'>
... another form content
</fieldset>
<% end %>
<% end %>
But it fails on
undefined method `data' for [:class, "form-horizontal"]:Array
I tried different association combinations etc, I feel lost.
Thanks
Levi
While i was trying to submit the form, following error occured: Validation failed: Images imageable must exist and render the same new.html.erb view.
If i comment the file field in new.html.erb. Product is being created successfully.
ProductsController:
def new
#product = Product.new
end
def create
#product = Product.create!(product_params)
if #product.save
redirect_to products_path, notice: "Product Created Successfully"
else
render "new"
end
end
def product_params
params.require(:product).permit(:name, :quantity, :price, images_attributes: [:id, :photo, :_destroy])
end
new.html.erb:
<%= nested_form_for #product, html: { multipart: true } do |f|%>
<h2>New</h2>
<P> <%= f.label :name %> <%= f.text_field :name %> </P>
<P> <%= f.label :quantity %> <%= f.text_field :quantity %> </P>
<P> <%= f.label :price %> <%= f.text_field :price %> </P>
<%= f.fields_for :images do |p| %>
<p> <%= p.label :photo %> <%= p.file_field :photo %> </p>
<%= p.link_to_remove "Remove Image" %>
<% end %>
<%= f.link_to_add "Add Image", :images %>
<%= f.submit "Add Product" %>
<% end %>
20160725102038_add_image_columns_to_imageable.rb:
class AddImageColumnsToImageable < ActiveRecord::Migration[5.0]
def up
add_attachment :images, :photo
end
def down
remove_attachment :images, :photo
end
end
Model:product.rb
class Product < ApplicationRecord
has_one :variant
has_many :images, as: :imageable, dependent: :destroy
accepts_nested_attributes_for :images, allow_destroy: true
end
Model:image.rb
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
In rails 5, belongs_to makes sure that the associated model must exist.
E.g In this polymorphic association, Image model has belongs_to :imageable and Product model has has_many :images.
So here in new.html.erb we are creating an image, but respective product not exist, so that's why error Image imageable must exist .
Solution
Add optional: true while making an association of belong_to in Image model.
Image Model now looks like:
class Image < ApplicationRecord
belongs_to :imageable, polymorphic: true, optional: true
has_attached_file :photo, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment :photo, content_type: { content_type: ["image/jpg", "image/jpeg", "image/png", "image/gif"] }
end
I'm facing this problem how to fix this issue?
This is my problem, always showing an error message:
This is my model:
validates :first_name, :presence => true, :length => { :in => 3..20 }
validates :last_name, :presence => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, format: { with: /\A[^#\s]+#([^#.\s]+\.)+[^#.\s]+\z/ }
# validates :passkey, :confirmation => true #password_confirmation attr
validates_length_of :passkey, :presence => true, :in => 6..20, :on => :register
This is my Controller:
def register
params.permit!
#jobseekers = Jobseeker.new(params[:jobseekers])
if #jobseekers.save
redirect_to home_path
else
render "register"
end
end
This is my view:
<%= form_for :jobseekers, url: register_path(#jobseekers), method: :patch do |f| %>
<%= f.text_field :first_name, placeholder: 'First Name'%>
<%= f.text_field :last_name, placeholder: 'Last Name'%>
<%= f.text_field :email, placeholder: 'Email'%>
<%= f.password_field :passkey, placeholder: 'Password'%>
<%= f.submit "Create Account" %>
<% end %>
<% if #jobseekers.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#jobseekers.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #jobseekers.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
I need show this error after click submit button, but now showing this error always.
Please help!
Now I'm using ruby 1.9.7 rails 4.2.5 & mysql2
The problem in your code is the controller action:
def register
params.permit!
#jobseekers = Jobseeker.new(params[:jobseekers])
if #jobseekers.save
redirect_to home_path
else
render "register"
end
end
if you take a look, then you don't just create a new object #jobseekers but try to save it right away. if #jobseekers.save will be false because the params[:jobseekers] is empty when you call the action for the first time. Since you have validations, it will automatically add errors, and your register view will be rendered with those errors. This is why usually there are 2 actions with forms- new and create.
To fix this split this into two actions
def register
#jobseekers = Jobseeker.new
end
def create_register
params.permit!
#jobseekers = Jobseeker.new(params[:jobseekers])
if #jobseekers.save
redirect_to home_path
else
render "register"
end
end
where create_register only has a post route and register has a get route (register will render the form for the first time, and then after submit the create_register will be called and render the form with errors if there are any)
This would then be your view(stating the method is not necessary in this case):
<%= form_for :jobseekers, url: create_register_path(#jobseekers) do |f| %>
<%= f.text_field :first_name, placeholder: 'First Name'%>
<%= f.text_field :last_name, placeholder: 'Last Name'%>
<%= f.text_field :email, placeholder: 'Email'%>
<%= f.password_field :passkey, placeholder: 'Password'%>
<%= f.submit "Create Account" %>
<% end %>
<% if #jobseekers.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#jobseekers.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #jobseekers.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
and your routes.rb entries:
get '/register', to: "jobseekers#register"
post '/register', to: "jobseekers#create_register"
Another take on Kkulikovskis' answer would be:
def register
params.permit!
#jobseekers = Jobseeker.new(params[:jobseekers])
return true if request.get? # <--- skip validations if not on form submit
if #jobseekers.save
redirect_to home_path
else
render "register"
end
end
I prefer this approach when the instantiation of #jobseeker is less trivial
PS params.permit! is a path to hell, don't do it
Can anybody please help me to resolve the following error using rails version-3.2.19 ?When i am submitting values to database this error is coming.
Error
ActiveModel::MassAssignmentSecurity::Error in UsersController#create
Can't mass-assign protected attributes: con_password
My code snippets are as follows.
views/users/new.html.erb
<center>
<h1>Enter your data</h1>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="form-div">
<%= form_for :user,:url => {:action => 'create'} do |f|%>
<p>
<%= f.label :Name %>
<%= f.text_field :name,placeholder:"Enter your name" %>
</p>
<p>
<%= f.label :Email %>
<%= f.email_field :email,placeholder:"Enter your Email" %>
</p>
<p>
<%= f.label :Password %>
<%= f.password_field :password,placeholder:"Enter your password" %>
</p>
<p>
<%= f.label :password %>
<%= f.password_field :con_password,placeholder:"Enter your password again" %>
</p>
<p>
<%= f.label :content %>
<%= f.text_field :content,placeholder:"Enter your content" %>
</p>
<p>
<%= f.submit "Create User",:class => 'submit' %>
</p>
<% end %>
</div>
</center>
controller/users_controller.rb
class UsersController < ApplicationController
def index
end
def new
#user=User.new
end
def show
end
def create
#user=User.new(params[:user])
if #user.save
flash[:notice]="User has created successfully"
flash[:color]="valid"
redirect_to :action => 'index'
else
flash[:alert]="User could not create"
flash[:color]="invalid"
render :new
end
end
end
model/user.rb
class User < ActiveRecord::Base
attr_accessible :content, :email, :name, :password
EMAIL_REGEX = /\A[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\z/i
validates :name, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :confirmation => true
validates_length_of :password, :in => 6..20, :on => :create
end
migrate\20150128062543_create_users.rb
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.string :password
t.string :content
t.timestamps
end
end
end
Please help me to solve this issue.
Instead of <%= f.password_field :con_password,placeholder:"Enter your password again" %>, you should name your field password_confirmation, because this is what your model expects if it has validates :password, confirmation: true:
<%= f.password_field :password_confirmation, placeholder: "Enter your password again" %>
You also have to add password_confirmation to attr_accessible in the model.