在表中查找记录并将id保存到Rails中的另一个表

时间:2016-06-08 21:13:47

标签: ruby-on-rails

我正在开发一个应用程序,用户可以在其中获得个人食物日记。

这非常简单:用户可以在Nutrients桌上搜索营养素(让我们说牛奶) - 目前通过一个非常简单的搜索表单 - 然后应该可以节省他的金额在第二个表上消耗了这种营养素(连同营养素_id),称为Diaries(将nutrient_id保存为外键,并将整数字段称为" amount")。

我的搜索有效。我也可以在Diaries中创建新记录,但我必须手动输入nutrient_id。

我现在的问题是如何让这件事变得轻松起来?理想情况下,用户会发现营养素点击它并将被重定向到显示此营养素的页面以及“#34; amount"和一个保存按钮,用于在日记表上保存两个信息(nutrient_id和amount)。

在一天结束时,我认为用户将被引导到我的日记控制器的新动作 - 问题是我的应用程序如何设置此操作的营养素_用于之前用户选择的营养素?

很抱歉,如果这是一个太简单的问题,但我几周前刚开始编码。

非常感谢您的帮助!

我的代码如下所示:

nutrient.rb

class Nutrient < ActiveRecord::Base
  has_many :diaries

  def self.search(search)
    where("name LIKE ?", "%#{search}%") 
  end

end

diary.rb

class Diary < ActiveRecord::Base
  belongs_to :nutrient
end

nutrients_controller.rb

class NutrientsController < ApplicationController
  before_action :set_nutrient, only: [:show, :edit, :update, :destroy]

  # GET /nutrients
  # GET /nutrients.json
  def index
    @nutrients = Nutrient.all
  end

  def search
    if params[:search]
      @nutrients = Nutrient.search(params[:search]).order("created_at DESC")
      if @nutrients.present?
        @nutrients
      else
        flash[:notice] = "Nutrient not found in database"
      end
    end
  end

  # GET /nutrients/1
  # GET /nutrients/1.json
  def show
  end

  # GET /nutrients/new
  def new
    @nutrient = Nutrient.new
  end

  # GET /nutrients/1/edit
  def edit
  end

  # POST /nutrients
  # POST /nutrients.json
  def create
    @nutrient = Nutrient.new(nutrient_params)

    respond_to do |format|
      if @nutrient.save
        format.html { redirect_to @nutrient, notice: 'Nutrient was successfully created.' }
        format.json { render :show, status: :created, location: @nutrient }
      else
        format.html { render :new }
        format.json { render json: @nutrient.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /nutrients/1
  # PATCH/PUT /nutrients/1.json
  def update
    respond_to do |format|
      if @nutrient.update(nutrient_params)
        format.html { redirect_to @nutrient, notice: 'Nutrient was successfully updated.' }
        format.json { render :show, status: :ok, location: @nutrient }
      else
        format.html { render :edit }
        format.json { render json: @nutrient.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /nutrients/1
  # DELETE /nutrients/1.json
  def destroy
    @nutrient.destroy
    respond_to do |format|
      format.html { redirect_to nutrients_url, notice: 'Nutrient was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def nutrient_params
      params.require(:nutrient).permit(:name)
    end
end

diaries_controller.rb

class DiariesController < ApplicationController
  before_action :set_diary, only: [:show, :edit, :update, :destroy]

  # GET /diaries
  # GET /diaries.json
  def index
    @diaries = Diary.all
  end

  # GET /diaries/1
  # GET /diaries/1.json
  def show
  end

  # GET /diaries/new
  def new
    @diary = Diary.new
  end

  # GET /diaries/1/edit
  def edit
  end

  # POST /diaries
  # POST /diaries.json
  def create
    @diary = Diary.new(diary_params)

    respond_to do |format|
      if @diary.save
        format.html { redirect_to @diary, notice: 'Diary was successfully created.' }
        format.json { render :show, status: :created, location: @diary }
      else
        format.html { render :new }
        format.json { render json: @diary.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /diaries/1
  # PATCH/PUT /diaries/1.json
  def update
    respond_to do |format|
      if @diary.update(diary_params)
        format.html { redirect_to @diary, notice: 'Diary was successfully updated.' }
        format.json { render :show, status: :ok, location: @diary }
      else
        format.html { render :edit }
        format.json { render json: @diary.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /diaries/1
  # DELETE /diaries/1.json
  def destroy
    @diary.destroy
    respond_to do |format|
      format.html { redirect_to diaries_url, notice: 'Diary was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def diary_params
      params.require(:diary).permit(:nutrient_id, :amount)
    end
end

的routes.rb

Rails.application.routes.draw do

  resources :diaries
  resources :nutrients do
    collection do
      get :search
    end
  end

_form.html.erb(对于新的日记记录)

<%= form_for(@diary) do |f| %>
  <% if @diary.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@diary.errors.count, "error") %> prohibited this diary from being saved:</h2>

      <ul>
      <% @diary.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :nutrient_id %><br>
    <%= f.number_field :nutrient_id %>
  </div>
  <div class="field">
    <%= f.label :amount %><br>
    <%= f.number_field :amount %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

1 个答案:

答案 0 :(得分:2)

有几种方法可以解决这个问题,一种最快且最有可能最好的方法是将diaries嵌套在nutrients下,因为日记belongs_to :nutrients

  resources :nutrients do
   resources :diaries
    collection do
      get :search
    end
  end

这样您的所有diaries路径方法都会接受@nutrient参数,您的路线就像:/nutrients/4/diaries/1

所以在你的diaries_controller中,你可以拥有:

class DiariesController < ApplicationController
   before_action :set_nutrient

   def new
    @diary = @nutrient.diaries.new
   end

   def create
    @diary = @nutrient.diaries.new(diary_params) # you can safely remove the nutrient_id from the strong params
    ... remaining logic here
   end
...
  private
   def set_nutrient
    @nutrient ||= Nutrient.find(params[:nutrient_id])
   end

   # You cans skip/ignore this method, if you don't want to be too strict
   def set_diary
    @diary ||= @nutrient.diaries.find(params[:id])
   end
end

然后在您看来,您可以:

<%= form_for([@nutrient, @diary]) do |f| %>
  <% if @diary.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@diary.errors.count, "error") %> prohibited this diary from being saved:</h2>

      <ul>
      <% @diary.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <div class="field">
    <%= f.label :amount %><br>
    <%= f.number_field :amount %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

正如我所提到的,还有其他方法可以做到这一点,因为你也可以使用hidden_fields,但这对我来说似乎是最干净的方式。 如果您并不总是希望嵌套您的日记路线,您可以预期:[{1}}和您的路线before_action上的[不应嵌套的操作列表,例如show] 。希望我能够帮助或让我知道您可能遇到的其他混淆。