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 anotherform
is not validhtml
. 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 theform_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 thetext_field
have changed, you could trigger anAJAX
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:
You have two approaches.
Approach 1: Through
controller
action filters. Intercept the user'semail
from theparams
in thecontroller
and update it. Something like:And update your form code as follows:
Approach 2: Through
model
callbacks. Using a combination ofattr_accessor
and thecallbacks
in the model.And update your form code as follows: