如何从一个提交更新两个_form? [英] How to update two _form from one submit?

查看:125
本文介绍了如何从一个提交更新两个_form?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果current_user没有单独的提交按钮,current_user如何更新他的电子邮件?



当前代码 p>

 <%= form_for(@challenge)do | challenge | %GT; 
<%= challenge.action%>
<%= challenge.send_email%>
<%end%>

<%= form_for(current_user)do | user | %GT;
<%= user.email%>
<%= user.submit%>
<%end%>

<%= form_for(@challenge)do | challenge | %GT;
<%= challenge.submit%>
<%end%>

整体构思

 <%= form_for(@challenge)do | challenge | %GT; 
<%= challenge.action%>
<%= challenge.send_email%>

<%= form_for(current_user)do | user | %GT; #或者以某种方式完全删除form_for(current_user),同时仍然能够更新form_for(@challenge)中的current_user.email
<%= user.email%>
<%end%>

<%= challenge.submit%>
<%end%>

_form图片





提供控制器代码来查看我们是否可以通过fields_for来完成这项工作。
$ b

challenges_controller

  class ChallengesController< ApplicationController 
before_action:set_challenge,仅:[:show::edit,:update,:destroy,::challenge,:mark_accomplished,:mark_completed,:create_freebie,:like]
respond_to:html,:json

def show
@challenge_to_deadline = current_user.challenges.group_by {| i | i.deadline} if current_user
@notable = @challenge
@notes = @ notable.notes
@note = Note.new
@commentable = @challenge
@评论= @ commentable.comments
@comment = Comment.new
@correct_user = current_user.challenges.find_by(id:params [:id])
结束

def new
@challenge = Challenge.new
respond_modal_with @challenge,位置:root_path
结束
$ b $ def编辑
结束

def创建
@challenge = Challenge.new(challenge_params)
if params [:step] =='2'
if current_user == nil
#如果没有用户,将生存期值存储到会话中。
session [:challenge_action] = challenge_params [:action]
session [:challenge_committed] = challenge_params [:committed]
session [:challenge_deadline] = [params [challenge] [deadline (3i)],params [challenge] [deadline(2i)],params [challenge] [deadline(1i)]]。join('/')
session [: challenge_date_started] = [params [challenge] [date_started(3i)],params [challenge] [date_started(2i)],params [challenge] [date_started(1i)]]。 join('/')
session [:challenge_order] = challenge_params [:order]
session [:challenge_days_challenged] = challenge_params [:days_challenged]
session [:challenge_why] = challenge_params [:why ]
session [:challenge_conceal] = challenge_params [:conceal]
redirect_to signup_path
else
@challenge = current_user.challenges.build(challenge_params)
if @challenge。隐藏== true
@ challenge.save
re direct_to root_path
if @ challenge.date_started.present?
flash [:info] ='习惯秘密保存!点击罢工1完成一天。'
else
flash [:info] ='目标挑战秘密保存! '
end
elsif
@ challenge.save
track_activity @challenge
redirect_to root_path
if @ challenge.date_started.present?
flash [:info] ='习惯保存的挑战!点击Strike 1完成一天。'
else
flash [:info] ='目标挑战保存! '
end
else
respond_modal_with @challenge
end
end
end
end

def update
@ challenge.update(challenge_params)
flash [:info] ='挑战更新'
respond_modal_with @challenge,位置:root_path
结束

私人

def set_challenge
@challenge = Challenge.find(params [:id])
结束

def challenge_params
params.require(:challenge).permit(
:action,
:为什么,
:like,
:截止日期,
:已完成,
: tag_list,
:隐藏,
:归档,
:触发器,
:错过日期,
:target,
:奖励,
:顺序,
:date_started,
:date_ended,
:days_challenged,
:completed_at,
:免费赠品,
:freebie_date,
:sen d_email => [],
:committed => [])
结束
结束

users_controller

  class UsersController< ApplicationController 
before_action:只有logged_in_user:[:index::edit,:update,:destroy,:following,:followers]
before_action:只有correct_user:[:edit,:update]

def show
@user = User.find(params [:id])
@past_challenges = @ user.challenges.publish.order(deadline ASC)。select {| challenge | challenge.deadline< Date.current如果challenge.deadline.present? }
@past_challenges_by_years = @ past_challenges.group_by {| t | t.deadline.beginning_of_year}
@present_oneshot_challenges = @ user.challenges.unaccomplished.publish.order(deadline ASC)。select {| challenge | challenge.deadline == Date.current if challenge.deadline.present? }
@present_habit_challenges = @ user.challenges.unaccomplished.publish.order(date_started DESC)。select {| challenge | challenge.date_started< = Date.tomorrow如果challenge.date_started.present? }
@future_challenges = @ user.challenges.unaccomplished.publish.order(deadline ASC)。select {| challenge | challenge.deadline> Date.current如果challenge.deadline.present? }
@future_challenges_by_years = @ future_challenges.group_by {| t | t.deadline.beginning_of_year}
@inspirations = @ user.inspirations.publish
end

def new
@user = User.new
end
$ b $ def创建
@user = User.new(user_params)
if @ user.save
action = session.delete(:challenge_action)
截止日期= session.delete(:challenge_deadline)
committed = session.delete(:challenge_committed)
date_started = session.delete(:challenge_date_started)
order = session.delete(:challenge_order)
days_challenged = session.delete(:challenge_days_challenged)
why = session.delete(:challenge_why)
conceal = session.delete(:challenge_conceal)
#如果deadline.present创建

@ user.challenges.create(操作:操作,截止日期:截止日期,原因:为什么,隐藏:隐藏,date_started:date_started,提交:提交,days_challenged:days_challenged)
结束
@user .send_welcome_email
log_in @user
redirect_to tutorial_url
flash [:info] ='让游戏开始! +挑战'添加另一个挑战'
else
渲染'新'
结束
结束

def编辑
@user = User.find (params [:id])
end
$ b def update
@user = User.find(params [:id])
if user.update_attributes(user_params )
redirect_to root_url
flash [:success] =设置更新
else
渲染'编辑'
结束
结束

private
$ b def user_params
if params [:conceal] = true
params.require(:user).permit(:time_zone,:name,:email,:tag_list ,::password,:conceal,inspirations_attributes:[:name,:tag_list,:conceal],activities_attributes:[:conceal,:action,:trackable_id,:trackable_type])
else
params [:user] [:conceal] = false
params.require(:user).permit(:time_zone,:name,:image,:tag_list,:email,:password,inspirations_attributes:[:name,:tag_list],activities_attributes: [:action,:trackable_ id,:trackable_type])
结束
结束

#确认登录用户。
def logged_in_user
除非logged_in?
store_location
flash [:danger] =请先登录
redirect_to root_url
结束
结束

#确认用户正确。
def correct_user $ b $ @user = User.find(params [:id])
redirect_to(root_url)除非current_user?(@user)
结束
结束


解决方案

嵌入表格在另一个窗体内无效 html 。在页面中可以有多种形式,但是它们不能相互嵌套。



如果您希望具有相同形式的不同模型的字段,根据这些模型之间的关联,您可以在 form_for 中使用 fields_for 来渲染这些模型中的表单字段。然后当表单被提交时,再次取决于模型之间的关联,您可以保存数据。



您也可以使用 javascript 并提交/更新表单的一部分。例如:当 text_field 的内容发生变化时,您可以触发 AJAX 请求并保存数据。 / p>

请参阅 FormHelper#fields_for 获取更多信息。



更新:

  class User< p>根据您在评论中的回复,您有以下模型: ActiveRecord :: Base 
has_many:挑战
结束

挑战< ActiveRecord :: Base
belongs_to:user
end

您有两种方法。方法1:通过控制器动作过滤器。从控制器中的 params 拦截用户的电子邮件和更新它。例如:

  class ChallengesController< ApplicationController 
before_action:update_user_email,如果:proc {| c | c.current_user.present? &安培;&安培; c.params [:邮箱] .present? }
private
def update_user_email
email = params [:email]
current_user.update_attribute(:email,email)
end
end

更新您的表单代码如下:

 <%= form_for(@challenge)do | challenge | %GT; 
#包含挑战字段

<%= text_field_tag:email,current_user.email%>

<%= challenge.submit%>
<%end%>

方法2:通过模型回调。在模型中使用 attr_accessor 回调的组合。

  class挑战< ActiveRecord :: Base 
belongs_to:user

attr_accessor:user_email
before_save:update_user_email,如果:: user_email_present?

保护
def user_email
self.user.email if self.user.present?
结束

def user_email_present?
self.user_email.present?
end
$ b $ def update_user_email
#根据您的控制器逻辑,看起来像
#`current_user`和``challenge`的`user`
#是一个一样的。所以你可以直接在`user`对象上更新
#`email`。
self.user.update_attribute(:email,self.user_email)
结束
结束

然后更新您的表单代码,如下所示:

 <%= form_for(@challenge)do | challenge | %GT; 
#包含挑战字段

<%= challenge.text_field:user_email,current_user.email%>

<%= challenge.submit%>
<%end%>


How can the current_user update his email, if he chooses, without having to have a separate submit button?

current code

<%= form_for(@challenge)  do |challenge| %>
  <%= challenge.action %>
  <%= challenge.send_email %>
<% end %>

<%= form_for(current_user)  do |user| %>
  <%= user.email %>
  <%= user.submit %>
<% end %>

<%= form_for(@challenge)  do |challenge| %>
  <%= challenge.submit %>
<% end %>

overall idea

<%= form_for(@challenge)  do |challenge| %>
  <%= challenge.action %>
  <%= challenge.send_email %>

  <%= form_for(current_user)  do |user| %> # Or somehow remove form_for(current_user) altogether while still being able to update current_user.email within the form_for(@challenge)
    <%= user.email %>
  <% end %>

  <%= challenge.submit %>
<% end %>

image of _form

Offering controllers code to see if we can make this work via fields_for

challenges_controller

class ChallengesController < ApplicationController
  before_action :set_challenge, only: [:show, :edit, :update, :destroy, :challenging, :mark_accomplished, :mark_completed, :create_freebie, :like]
  respond_to :html, :json

  def show
    @challenge_to_deadline = current_user.challenges.group_by {|i| i.deadline} if current_user
    @notable = @challenge
    @notes = @notable.notes
    @note = Note.new
    @commentable = @challenge
    @comments = @commentable.comments
    @comment = Comment.new
    @correct_user = current_user.challenges.find_by(id: params[:id])
  end

  def new
    @challenge = Challenge.new
    respond_modal_with @challenge, location: root_path
  end

  def edit
  end

  def create
    @challenge = Challenge.new(challenge_params)
    if params[:step] == '2'
      if current_user == nil
        # If there is no user, store the lifetime values to the session.
        session[:challenge_action] = challenge_params[:action]
        session[:challenge_committed] = challenge_params[:committed]
        session[:challenge_deadline] = [params["challenge"]["deadline(3i)"], params["challenge"]["deadline(2i)"], params["challenge"]["deadline(1i)"]].join('/')
        session[:challenge_date_started] = [params["challenge"]["date_started(3i)"], params["challenge"]["date_started(2i)"], params["challenge"]["date_started(1i)"]].join('/')
        session[:challenge_order] = challenge_params[:order]
        session[:challenge_days_challenged] = challenge_params[:days_challenged]
        session[:challenge_why] = challenge_params[:why]
        session[:challenge_conceal] = challenge_params[:conceal]
        redirect_to signup_path
      else
        @challenge = current_user.challenges.build(challenge_params)
        if @challenge.conceal == true
          @challenge.save
          redirect_to root_path
          if @challenge.date_started.present?
            flash[:info] = 'habit Challenge secretly saved! Click "Strike 1" upon incompleting a day.'
          else
            flash[:info] = 'goal Challenge secretly saved! Click checkmark upon completing it.'
          end
        elsif
          @challenge.save
          track_activity @challenge
          redirect_to root_path
          if @challenge.date_started.present?
            flash[:info] = 'habit Challenge saved! Click "Strike 1" upon incompleting a day.'
          else
            flash[:info] = 'goal Challenge saved! Click checkmark upon completing it.'
          end
        else
          respond_modal_with @challenge
        end
      end
    end
  end

  def update
    @challenge.update(challenge_params)
    flash[:info] = 'Challenge updated'
    respond_modal_with @challenge, location: root_path
  end

private

  def set_challenge
    @challenge = Challenge.find(params[:id])
  end

  def challenge_params
    params.require(:challenge).permit(
      :action,
      :why, 
      :like, 
      :deadline, 
      :accomplished, 
      :tag_list, 
      :conceal,
      :archive,
      :trigger,
      :missed_days,
      :target, 
      :reward,
      :order,
      :date_started,
      :date_ended,
      :days_challenged,
      :completed_at,
      :freebie,
      :freebie_date, 
      :send_email => [],
      :committed => [])
  end
end

users_controller

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy, :following, :followers]
  before_action :correct_user,   only: [:edit, :update]

  def show
    @user = User.find(params[:id])
    @past_challenges = @user.challenges.publish.order("deadline ASC").select{ |challenge| challenge.deadline < Date.current if challenge.deadline.present? }
    @past_challenges_by_years = @past_challenges.group_by { |t| t.deadline.beginning_of_year }
    @present_oneshot_challenges = @user.challenges.unaccomplished.publish.order("deadline ASC").select{ |challenge| challenge.deadline == Date.current if challenge.deadline.present? }
    @present_habit_challenges = @user.challenges.unaccomplished.publish.order("date_started DESC").select{ |challenge| challenge.date_started <= Date.tomorrow if challenge.date_started.present? }
    @future_challenges = @user.challenges.unaccomplished.publish.order("deadline ASC").select{ |challenge| challenge.deadline > Date.current if challenge.deadline.present? }
    @future_challenges_by_years = @future_challenges.group_by { |t| t.deadline.beginning_of_year }
    @inspirations = @user.inspirations.publish
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      action = session.delete(:challenge_action)
      deadline = session.delete(:challenge_deadline)
      committed = session.delete(:challenge_committed)
      date_started = session.delete(:challenge_date_started)
      order = session.delete(:challenge_order)
      days_challenged = session.delete(:challenge_days_challenged)
      why = session.delete(:challenge_why)
      conceal = session.delete(:challenge_conceal)
      # Create
      if deadline.present?
        @user.challenges.create(action: action, deadline: deadline, why: why, conceal: conceal, date_started: date_started, committed: committed, days_challenged: days_challenged)
      end
      @user.send_welcome_email
      log_in @user
      redirect_to tutorial_url
      flash[:info] = 'Let the games begin! Add another challenge with + Challenge'
    else
      render 'new'
    end
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      redirect_to root_url
      flash[:success] = "Settings updated"
    else
      render 'edit'
    end
  end

  private

  def user_params
    if params[:conceal] = true
      params.require(:user).permit(:time_zone, :name, :email, :tag_list, :password, :conceal, inspirations_attributes: [:name, :tag_list, :conceal], activities_attributes: [:conceal, :action, :trackable_id, :trackable_type])
    else
      params[:user][:conceal] = false
      params.require(:user).permit(:time_zone, :name, :image, :tag_list, :email, :password, inspirations_attributes: [:name, :tag_list], activities_attributes: [:action, :trackable_id, :trackable_type])
    end
  end

  # Confirms a logged-in user.
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please sign in first"
        redirect_to root_url
      end
    end

    # Confirms the correct user.
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end
end

解决方案

Embedding form within another form is not valid html. There can be multiple forms with in a page, but they cannot be embedded within each other.

If you want to have fields for different models with in the same form, depending upon the association between those models, you could make use of fields_for within the form_for to render the form fields from those models. And then when the form is submitted, again depending upon the associations between the models, you could persist the data.

You could also make use of javascript and submit/update parts of the form. For example: when the contents of the text_field have changed, you could trigger an AJAX request and persist the data.

Refer to FormHelper#fields_for for more info.

Update:

Based on your response in the comments, as you have the following models:

class User < ActiveRecord::Base
  has_many :challenges
end

class Challenge < ActiveRecord::Base
  belongs_to :user
end

You have two approaches.

Approach 1: Through controller action filters. Intercept the user's email from the params in the controller and update it. Something like:

class ChallengesController < ApplicationController
  before_action :update_user_email, if: proc {|c| c.current_user.present? && c.params[:email].present? }
  private
  def update_user_email
    email = params[:email]
    current_user.update_attribute(:email, email)
  end
end

And update your form code as follows:

<%= form_for(@challenge)  do |challenge| %>
  # include fields for challenge

  <%= text_field_tag :email, current_user.email %>

  <%= challenge.submit %>
<% end %> 

Approach 2: Through model callbacks. Using a combination of attr_accessor and the callbacks in the model.

class Challenge < ActiveRecord::Base
  belongs_to :user

  attr_accessor :user_email
  before_save :update_user_email, if: :user_email_present?

  protected
  def user_email
    self.user.email if self.user.present?
  end 

  def user_email_present?
    self.user_email.present?
  end

  def update_user_email
    # based on your logic in controller, looks like the 
    # `current_user` and the `user` of the `challenge` 
    # are one and the same. So you could directly update
    # `email` on the `user` object.
    self.user.update_attribute(:email, self.user_email)
  end
end

And update your form code as follows:

<%= form_for(@challenge)  do |challenge| %>
  # include fields for challenge

  <%= challenge.text_field :user_email, current_user.email %>

  <%= challenge.submit %>
<% end %> 

这篇关于如何从一个提交更新两个_form?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆