Ruby on Rails Adding Object to Database through Forms Error - ruby
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.
Related
Simple_form issues
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" %>
Error: Validation failed: Images imageable must exist , rails-5.0 , paperclip-5
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
Always showing error message on the form with Ruby on Rails
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
How can I solve MassAssignmentSecurity error using rails version 3.2.19
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.
NoHandlerError Paperclip on ruby on rails 3.2.1
I am trying to make available to upload a multiple pictures with paperclip. I am following this tutorial: http://www.emersonlackey.com/article/paperclip-with-rails-3 Unfortunately I have error: No handler found for "apple_mac-1280x800.jpg" Asset.rb class Asset < ActiveRecord::Base belongs_to :post has_attached_file :asset, :styles => { :small => "100x100", :original => '800x600>'} end Post.rb class Post < ActiveRecord::Base has_many :assets accepts_nested_attributes_for :assets, :allow_destroy => true end Posts_controller.rb def new #post = Post.new 5.times { #post.assets.build } respond_to do |format| format.html # new.html.erb format.json { render json: #post } end end def edit #post = Post.find(params[:id]) 5.times { #post.assets.build } end #Post form <% create_url = {:url=>{:action=>"create"}} if #post.new_record? %> <% form_for #post, :html => {:multipart => true} do |t| %> <p> <%= t.label :title, 'Virsraksts:' %> <%= t.text_field :title %> </p> <p> <%= t.label :content, 'Teksts:' %> <%= t.text_area :content, :class => "mceEditor"%> </p> <%= t.fields_for :assets do |asset_fields| %> <% if asset_fields.object.new_record? %> <p> <%= asset_fields.file_field :asset %> </p> <% end %> <% end %> <%= t.submit %> <% end %> <%end%> Problem solved by changing <%= t.fields_for :assets do |asset_fields| %> to <%= f.fields_for :assets do |asset_fields| %> But could someone explain why?