rubypostgresqlformsruby-on-rails-6nomethoderror

Ruby on Rails Adding Object to Database through Forms Error


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

Solution

  • 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.