【问题标题】:undefined method `before_save' for YearsController:Class Did you mean? before_actionYearsController:Class 的未定义方法“before_save”你是说什么? before_action
【发布时间】:2020-01-28 21:30:25
【问题描述】:

错误:undefined method 'before_save' for YearsController:Class Did you mean? before_action

https://guides.rubyonrails.org/active_record_callbacks.html 谈到“可以创建、更新和销毁对象”,如果通过 ActiveStorage 添加的图像已经存在,我想中断该过程以避免重复。 before_save 是可用的回调之一。

导轨 (6.0.0)。我对 ActiveRecord 回调没有经验,但 https://api.rubyonrails.org Active Record 回调列出了 before_save,但不是 before_action。但是before_action. 没有错误我什至不确定何时需要激活回调,但我正在努力解决问题。允许哪些回调?并且不确定before_action 会是什么。

years_controller.rb

class YearsController < ApplicationController
  helper_method :sort_column, :sort_direction
  before_action :set_year, only: [:show, :edit, :update, :destroy] # 2019.06.20 Can't see that this is being used anywhere
  before_action :set_s3_direct_post, only: [:new, :edit, :create, :update]
# before_action :dup_check, only: [:new, :edit, :update] # runs, but not what I think I want
before_save :dup_check, only: [:new, :edit, :update] # undefined method `before_save' for YearsController:Class Did you mean?  before_action  
  PAGE_SIZE = 10

  def index
    @years = Year.order(sort_column + " " + sort_direction)

     respond_to do |format|
      format.html {}
      format.json { render json: @years }
    end
  end

  def documents
    @years = Year.all
  end

  def map_one  # mapping one connection/year
    # need to use the year passed in and then make it for a year
    years = Year.where( year_date: '1865-01-01' .. '1995-12-31' )
  end

  def search
    # Copeland except within the else
    @page = (params[:page] || 0).to_i
    if params[:keywords].present?
      @keywords = params[:keywords]
      year_search_term = YearSearchTerm.new(@keywords)
      @years = Year.where(
          year_search_term.where_clause,
          year_search_term.where_args).
        order(year_search_term.order).
        offset(PAGE_SIZE * @page).limit(PAGE_SIZE)
    else
      @years = Year.order(sort_column + " " + sort_direction)
    end
    respond_to do |format|
      format.html {}
      format.json { render json: @years }
    end
  end


  def summary
    @years = Year.order(:year_date)
    respond_to do |format|
      format.html {}
      format.json { render json: @years }
    end
  end

  def show
   end

  # GET /years/new
  def new
    # All from Tutorial Points Tutorial
    @year = Year.new({:year_date => "1900-09-01"}) # This is default. Helps to change when going through a group.
    @locations = Location.all
    @people    = Person.all
  end

  # GET /years/1/edit
  def edit
     @positions = Position.all # Needed for Positions/ Titles list to work, However not added to database
  end

  # POST /years
  # POST /years.json
  def create
    @year = Year.new(year_params)
    respond_to do |format|
      if @year.save
        format.html { redirect_to @year, notice: 'Connection was successfully created.' }
        format.json { render :show, status: :created, location: @year }
      else
        format.html { render :new }
        format.json { render json: @year.errors, status: :unprocessable_entity }
      end
    end
    repopulateResidResto()
  end

  # PATCH/PUT /years/1
  # PATCH/PUT /years/1.json
  def update
    respond_to do |format|
      if @year.update(year_params)
        format.html { redirect_to @year, notice: 'Connection was successfully updated.' }
        format.json { render :show, status: :ok, location: @year }
      else
        format.html { render :edit }
        format.json { render json: @year.errors, status: :unprocessable_entity }
      end
    end
    repopulateResidResto() # nice to have some error handling here
  end

  # DELETE /years/1
  # DELETE /years/1.json
  def destroy
    @year.destroy
    respond_to do |format|
      format.html { redirect_to years_url, notice: 'Connection was successfully destroyed.' }
      format.json { head :no_content }
    end
    repopulateResidResto()
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_year
      @year = Year.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def year_params
      params.require(:year).permit(:year_date, :person_id, :location_id, :resto, :resto_name, :resid, :title, :source, :source_url, :ref_image, :doc_image , :ref_url, :notes, :ref_url, :caption, documents: []) # document replaces _images, brackets for has many
     end

    def set_s3_direct_post
        @s3_direct_post = S3_BUCKET.presigned_post(key: "uploads/#{SecureRandom.uuid}/${filename}", success_action_status: '201', acl: 'public-read')
    end

    def dup_check
     # if active_storage_blobs(:checksum ) == an existing blob
     # let's first run a test seeing if a know checksum exists. That works. Now get the existing checksums     
     test_checksum = '0M4nc4nuUaVuqo3+sJw+Lg==' # will get for selected image at some point

     test_checksum == '0M4nc4nuUaVuqo3+sJw+Lg==' ? (puts "years_controller:158. test_checksum #{test_checksum} does exist") : (puts "years_controller:158. test_checksum #{test_checksum} does not exist") # Need the ()
      puts "years_controller:160. dup_check entered via before_action. before_save results in an errro"
    end

    # NOT CLEAR ANY OF THIS IS NEEDED. BUT PUT IT IN AGAIN WHEN CREATE DIDN'T WORK
    def person_params
      params.require(:person).permit(:last_name, :given_name, :full_name, :full_name_id)
    end

    def sort_column
      Year.column_names.include?(params[:sort]) ? params[:sort] : "year_date" # it does matter what this last field is.
    end

    def sort_direction
      %w[asc desc].include?(params[:direction]) ? params[:direction] : "asc"
    end

end

year.rb

class Year < ApplicationRecord
  belongs_to :location
  belongs_to :person
  has_many   :resto_resid_lines
  has_many_attached :documents # ActiveStorage
  has_rich_text :caption # ActionText 2019.12.05 not implemented because form needs major changes to work
  scope :with_eager_loaded_documents, -> { eager_load(documents_attachments: :blob) } 

  default_scope -> { order(:year_date) } 
  validates :person_id,   presence: true
  validates :location_id, presence: true 

  validates_presence_of :resto, {:if => :resto_name?, message: 'Click on Restaurant (above) since a restaurant name has been selected' } 
  validates :resto, :presence => { :if => :resto_name?, message: 'Select Restaurant since a restaurant name has been specified' } # is this the same as above, but not working?


  def self.search(search)
    where("year_date ILIKE ? OR resto ILIKE ? OR resto_name ILIKE ? OR resid ILIKE ? OR title ILIKE ? OR source ILIKE ? OR source_url ILIKE ? OR ref_url ILIKE ? OR notes ?", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%") 
  end

  def map_popup
    "#{person.given_name} #{person.last_name} was a #{title} at #{location.address} in #{year_date.to_formatted_s(:month_year)}"
  end

  def next
    Year.where("id > ? AND year_date = ?", id, year_date).first
  end

  def previous
    Year.where("id < ? AND year_date = ?", id, year_date).last
  end

  private

  def resid_xor_resid
    if [resto, resid].compact.count != 1
      errors.add(:base, "Select Residence or Restaurant, but  not both")
    end
  end

 end

很多麻烦,因为这是我的第一个应用程序,我已经为此工作多年。

【问题讨论】:

  • before_save 是模型级别,before_action 是控制器级别。可以发YearsControlleryear 模特吗?
  • @7urkm3n 完成。感谢收看。
  • 它看起来对我来说很好,什么时候发生?
  • @7urkm3n。我意识到我需要消化你说的话。这是我想要的控制器动作。所以我需要弄清楚这一点。谢谢。
  • @7urkm3n 谢谢你的建议。我需要自己尝试一下并对文档进行一些研究。可能最终会出现在新帖子中。

标签: ruby-on-rails activerecord callback ruby-on-rails-6 before-save


【解决方案1】:

你说过你会在回来之前自己研究一下。

您缺少的是某些回调特定于您调用它们的类的类型。我希望你现在很清楚,保存是模型特有的东西,控制器与它无关(@record.save,还记得吗?)。另一方面,before_actionafter_action 是控制器中使用的,因为控制器具有操作。参考:Ruby-on-Rails guides

解决方案:

  1. 由于重复性与模型有关,您应该将 before_save 或 before_create(我猜已弃用)添加到模型而不是第二种解决方案:
class Year < ApplicationRecord
  before_save :is_duplicate?

  private

  def is_duplicate
    return Year.where([the_attributes_that_make_it_duplicate]).present? # or something like that :P
    # throw :abort or return false (I guess you can't through in this case)
  end
end
  1. 您可以在操作前检查重复性,如果在控制器中重复则重定向回来,例如:
class YearsController < ApplicationController
  before_action :dup_check

  private

  def dup_check
    set_year
    redirect_to your_desired_path if Year.where([the_attributes_that_make_it_duplicate]).present?
  end
end

【讨论】:

  • 不幸的是,这对我来说并不明显——需要学习更多。从顶部看起来更像控制器 我正在努力解决的另一个问题是 ActiveStorage 模型和控制器没有暴露给我?我可以运行 Select * from active_storage_blobs where checksum = '0M4nc4nuUaVuqo3+sJw+Lg==' 并获得预期的响应,但我不知道如何在 Rails 中执行此操作(目前)。当然,Rails 可以访问图像;只需要更深入地研究它。我正在阅读您的指南参考以及guides.rubyonrails.org/active_record_querying.html 等谢谢
猜你喜欢
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-24
  • 1970-01-01
相关资源
最近更新 更多