I have a modal on a searches/show page:
<button name="button" type="button">
<a class="nav-link" data-toggle="modal" data-target="#emailFriendModal" href="">Email Results to Friend</span></a>
</button>
On click, the modal correctly brings up this partial (most of the code redacted for brevity):
<div class="modal fade" id="emailFriendModal">
...
<div class="mx-auto text-left column">
<%=form_with id: :friend_email_form, url: friend_emails_create_path do |f|%>
...
<%= recaptcha_tags %>
<div class="actions">
<%= f.submit "Send Email", class: 'btn btn-primary', "onclick":"submit_form();", "data-dismiss":"modal"%>
</div>
<script>
function submit_form() {
document.getElementById('friend_email_form').submit();
}
</script>
<%end%>
</div>
But on submit, the object is not sent to the friend_emails Controller:
class FriendEmailsController < ApplicationController
def new
#friend_email = FriendEmail.new
end
def create
#friend_email = FriendEmail.new(message: params[:message], email: params[:email], email2: params[:email2], path: params[:path])
if #friend_email.save
redirect_back fallback_location: root_path, notice: "Your email has been sent"
else
redirect_back fallback_location: root_path, notice: "Sorry, something went wrong, please try again"
end
end
def friend_email_params
params.require(:friend_email).permit(:message,:email,:email2,:path)
end
end
When the "Email a Friend" button is clicked, the correct partial pops up, but when the form is submitted, a Tour object is created (not a Friend_email object!!). The tour message is displayed, a tour email is sent. On submit the the info is completely bypassing the Friend_emails controller and going straight to the Tour controller.
Routes:
post "friend_emails/create"
post "tours/create"
Rake Routes:
friend_emails_create POST /friend_emails/create(.:format) friend_emails#create
tours_create POST /tours/create(.:format) tours#create
Tours Controller in case its helpful:
class ToursController < ApplicationController
def index
#tours = Tour.all
end
def new
#tour = Tour.new
end
def create
#tour = Tour.new(day: params[:day], time: params[:time], user_id: params[:user_id], listing_id: params[:listing_id], school_id: params[:school_id],
email: params[:email])
if #tour.save
redirect_back fallback_location: root_url, notice: "Your tour request has been sent; we will be in touch soon with confirmation."
else
redirect_back fallback_location: root_url, notice: "#{#tour.errors.full_messages}"
end
end
def destroy
#tour = Tour.find(params[:id])
#tour.destroy
redirect_back fallback_location: root_url, notice: "Your Tour has been Cancelled"
end
def tour_params
params.require(:tour).permit(:tour_req, :user_id, :listing_id, :school_id, :email, :day, :time)
end
end
And Finally, this is an excerpt from the Application Layout which holds the partials.
<%= yield %>
<% unless user_signed_in? %>
<%= render partial: 'devise/registrations/new' %>
<%= render partial: 'devise/sessions/new' %>
<% end %>
<%= render partial: 'friend_emails/new'%>
<%= render partial: 'tours/new'%>
I figured out the problem. I had two modals in the application layout and the code referenced the same javacript submit() function. The fix was to change the name of the submit() function like this:
<div class="actions">
<%= f.submit "Send Email", class: 'btn btn-primary', "onclick":"submit_form2();", "data-dismiss":"modal"%>
</div>
<script>
function submit_form2() {
document.getElementById('friend_email_form').submit();
}
</script>
Now we have two javascript functions, submit_form() and submit_form2() and everything works as it should.
Related
i'm newbie in Ruby on rails.
I'm doing CRUD for Articles and have a question: how to keep url and data's form when i create or update a article but it invalid validate?
And if they resolved, how to keep _form.html.erb to use for create and edit view.
I tried some solution in stackoverflow but there are no solution resolved all my problems above.
Here is new article view:
https://ibb.co/bdm4Hxj
You see, url change from /articles
https://ibb.co/wQ6Vxpz
inspect, we see action: /articles, method: post
https://ibb.co/LPJzvLr
and routes in rails:
https://ibb.co/rs1T1PY
_form.html.erb for create and edit view:
<%= form_for #article, html: {class: "form-horizontal"}, local: true do |f| %>
<div class="form-group">
<%= f.label :title, "Title", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_field :title, class: "form-control" %>
</div>
</div>
<div class="form-group">
<%= f.label :text, "Text", class: "col-md-2 control-label" %>
<div class="col-md-6">
<%= f.text_area :text, class: "form-control"%>
</div>
</div>
<div class="form-group">
<div class="col-lg-offset-4">
<a class="btn btn-success" href="<%= articles_path %>">Back</a>
<%= f.submit action_name.capitalize, class: "btn btn-success" %>
</div>
</div>
<% end %>
My ArticlesController:
class ArticlesController < ApplicationController
def index
#articles = Article.all
end
def new
#article = Article.new
end
def show
#article = get_by(:id)
end
def create
#article = Article.new(article_params)
if #article.save
flash[:success] = 'Create success!'
redirect_to articles_path
else
flash[:warning] = 'Something went wrong!'
render :new
end
end
def edit
#article = get_by(:id)
end
def update
#article = get_by(:id)
if #article.update(article_params)
flash[:success] = 'Update success!'
redirect_to articles_path
else
flash[:warning] = 'Update failed!'
render :edit
end
end
def destroy
#article = get_by(:id)
if #article.destroy
flash[:success] = 'Delete success!'
redirect_to articles_path
else
flash[:warning] = 'Delete failed!'
render :new
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
def get_by(id)
Article.find(params[id])
end
end
Thank you and sorry because of my bad english!
Your examples look pretty much what comes out of a scaffold, which is not too bad a start when learning how things can work (rails g scaffold article).
The relevant controller and views are then set up to do exactly what you are asking for: The controller holds a local variable (#article) ready for the view (ultimately _form.erb), whether or not the objects data is valid.
I wonder: What exactly happens? When you save with invalid data, the form should show up with the invalid data still in place. If you compare your form with the one that is created by the scaffold, you will notice that some output regarding validation errors is missing in your example. Try to add it, or start from scratch to see how it looks like.
When the data is valid and you still want the controller to show the user the form after hitting save, instead of redirect_to ... just render :edit.
Ruby on Rails, Simple Form.
I have a contact/Message partial on several pages (product#index#show, static ‘services’ page) — when someone fills out the partial form and submits, I want the Message#new page to load with partial data prefilling the larger contact form without creating a new message and sending the action mailer.
Other SO solutions are for multi-step forms, wizards, or passing data through URL.
Here's my code:
_Shortcontact (the partial)
<div class="short_contact_wrapper">
<h4 id="short_container_title">Contact Us</h4>
<div class="contact-container">
<%= simple_form_for(message) do |f| %>
<div class="form-row-2">
<%= f.input :contactfirstname, label: false, placeholder: "* First Name", presence: true, :input_html => { :class => 'input_string' } %>
<%= f.input :contactlastname, label: false, placeholder: "* Last Name" %>
</div>
<div class="form-row-2">
<%= f.input :email, label: false, placeholder:"* Email" %>
<%= f.input :phone, label: false, placeholder: "* Phone" %>
</div>
</div>
<div class="contact-container">
<%= f.input :product_app, label: "Product Application Category", collection: ["Drones", "5G Telecom", "Thin Battery", "Auto Warehouse", "Robotics", "Wearables", "Electric Vehicles", "Industrial Personal Computers (Military)", "Industrial Personal Computers(Medical)", "Consumer Electronics", "Uninterruptible Power System", "Internet of Things", "Power Bank", "Other" ] %>
<%= f.input :batteryapp, label: false, placeholder: "Please describe the product and how you\'ll use the lithium ion battery or cell." %>
<div class="bottom_container" style="display: flex; justify-content: center;">
<%= f.button :submit, "Submit", class: 'contactbutton' %>
</div>
<% end %>
</div>
</div>
In my Product controller #Edit and #Show:
before_action :build_message, only: [:index, :new, :show]
def index
#products = Product.all
end
def new
#product = Product.new
# build nested models
#product.product_specs.build
#product.specifications.build
end
def create
#product = Product.new(product_parameters)
#product.category_id = product_parameters[:category_id]
# setting product stuff for TESTING
#product.picture = "products/IPC_tablet.png"
#product.iconblack = "icons/products/icon_IPC_black.png"
if #product.save!
flash[:success] = "You have saved the #{#product.name} product"
redirect_to product_path(#product)
else
flash.now[:error] = "Product was not saved"
render "new"
end
end
def show
#product_specs = #product.product_specs
end
def edit
# build nested models
#product.product_specs.build
#product.specifications.build
end
def build_message
#message = Message.new
end
Message Controller
def new
#message = Message.new
#message.build_company
puts "#{params[:message].inspect}"
puts "are there parameters?"
puts "#{#message.inspect}"
end
def create
#message = Message.new(message_parameters)
respond_to do |format|
if #message.save!
#send through mailer
MessageMailer.send_message(#message).deliver_now
format.html {redirect_to message_path(#message)}
else
format.html {render action: 'new'}
format.json {render json: #message.errors, status: :unprocessable_entity }
end
end
end
**Edit: Example of where I call _shortform: Layout/products **
<%= render '/partials/head' %>
<%= render '/partials/header' %>
<%= render 'layouts/messages' %>
<div class="product_layout_container">
<div class="layout_sidebar">
<%= link_to products_path do %>
<h4>Products</h4>
<% end %>
<%= render 'products/productsidebar', locals: {products: #products, categories: #categories } %>
</div>
<div class="product_yield">
<%= yield %>
</div>
</div>
<div class="page_container bottom_container">
<% unless user_signed_in? %>
<%= render partial: 'messages/shortcontact', locals: { message: #message }%>
<% end %>
</div>
<%= render '/partials/footer' %>
<%= render '/partials/foot' %>
I need help figuring out how to structure my partial form, or how I can prefill the Message#new form.... Thanks!
Start by adding an additional route (POST /messages/new):
resources :messages do
post :new, on: :collection
end
This is somewhat optional. Its possible to just setup this up with just GET as well but the parameters will be sent in the URL.
You can then simply bind the parameters to the model instance via strong the strong parameters.
class MessagesController
# ...
def new
#message = Message.new
# We need a condition here to avoid a parameter missing error
#message.assign_attributes(message_parameters) if params[:message]
end
end
You also have to manually override the path of the form:
simple_form_for(message, url: new_message_path)
I have a form and a div for showing the message which is sent by form. I have to refresh the page after sending a message by form to see the messages in my div. However, I want to see the messages in div without refreshing the page, like a chatroom. I tried to use Ajax but I couldn't make it.
Here is my form:
<%= form_for #message, remote:true do |f| %>
<%= f.text_area :body, class: "form-control", placeholder: "Enter Message" %>
<%= f.submit "Send", class: 'btn btn-primary btn-lg' %>
<% end %>
And here is my controller
class MessagesController < ApplicationController
def index
#messagesAll = Message.all
#message = Message.new
end
def new
#message = Message.all
end
def create
#message = Message.new(params.require(:message).permit(:user, :body))
if #message.save
respond_to do |format|
format.js {}
format.html {redirect_to messages_url}
end
else
render 'new'
end
end
end
And here is my div:
<div class="panel-body" id="messages-div">
<ul class="media-list">
<% #messagesAll.each do |post| %>
<li class="media">
<%= post.body %>
</li>
<% end %>
</ul>
</div>
Could anyone help me? Thank you.
Assuming you have a div with an id of messages that you're rendering the messages in e.g.
<div id="messages">
<%= render #messages %>
</div>
On your create action rails will look for a create.js.erb file. So what you want is this in your controller:
respond_to do |format|
format.js {}
format.html {redirect_to messages_url}
end
Then have a create.js.erb file:
$('#messages').append('<%= j render #message %>');
Edit: In your specific case you would need to target the ul. So your create.js.erb would be
$('#messages-div ul.media-list').append('<li class="media"><%= j #message.body %></li>');
j is just a shortcut for escape_javascript. Docs
That should get you started, but you'll want to do something else via ajax if the message isn't saved.
After a user logs in, I'm trying to collect additional info to update in the data base
this is my controller
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def additional_info
#user = User.find params[:id]
end
def update
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
def create
#user = User.new(user_params)
if #user.save
#session[:user_id] = #user.id
#UserMailer.welcome_email(#user).deliver
sign_in #user
redirect_to additional_info_path(#user)
flash[:success] = "Welcome to InYourShoes!"
else
render'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
def user_addinfo
params.require(:user).permit(:year)
end
end
the error occurs at the def update function if #user.update(user_addinfo), rails says its undefined.
def user_addinfo is a action method and def additional_info is the actual page
the view for the page:
<div class="row">
<div class="col-xs-12 col-sm-6 col-sm-offset-3">
<%= form_for(#user, :html => {:class => 'form-horizontal'}) do |f| %>
<fieldset>
<p>Do you have experience in Business? If yes, select one of the following:
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Select one <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Entrepreneurship</li>
<li>Investments</li>
<li>Management</li>
<li class="divider"></li>
<li>All of the Above</li>
</ul>
</div><!-- /btn-group -->
<%= f.text_field :year , :class => "form-control", :placeholder => "Years of experience" %>
</div>
</p>
<div class = "center form-actions">
<%= f.submit "Submit", class: "btn btn-lg btn-primary" %>
</div>
</fieldset>
<% end %>
</div>
</div>
am i saving the #user in the wrong place? I'm still new to the concept of #variablename instance variable... help and explanation is greatly appreciated
It is because you did't initialize the #user in "update" method.
Usually you need to do something like you did in "show" method.
#user = User.find(params[:id])
You current code, #user in "update" method is nil because you didn't assign any value to it. And a "nil" variable don't have the method "update".
You probably shouldn't try to overload your update function to capture the functionality of both edit and update (which you are doing, the other answers overlooked this). But the reason #user is nil upon form submission is probably because of this line:
render action: 'additional_info'
I'm guessing that line isn't doing what you expect. Rather than run the addition_info action and rendering the form, I believe that is simply performing the render. You probably want to redirect_to 'additional_info' and add a route for it if needed. Then you can ensure that the form is submitting the #user object correctly back to the update function.
You have to fetch the user additional information before updating it
def update
#user = User.find(params[:id])
if #user.update_attributes(user_addinfo)
#your redirection
else
#your redirection
end
end
def update
self.additional_info
if #user.update(user_addinfo)
redirect_to user_path(#user), notice: 'User was successfully updated.'
else
render action: 'additional_info'
end
end
#user doesn't exist with update, you'll need to create it first, which you've kind of done already
I have 2 controllers: DocumentsController and DashboardController
After the user login successful, he is redirected to dashboard_path, which has a form to create a 'fast document' like this
<%= form_for #document, :html => {:class => 'well'} do |f| %>
<% if #document.errors.any? %>
<div id="alert alert-block">
<div class="alert alert-error">
<h2>Couldn't create your doc. :(</h2>
<ul>
<% #document.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
<label>A lot of fields</label>
<%= f.text_field :fields %>
<div class="form-actions">
<%= f.submit 'Create document', :class => 'btn btn-large' %>
</div>
<% end %>
but when an exception happen (like the user forgot to fill a field), I would like to show these exceptions, not just an alert saying 'Error'...actually, I didn't found a way to do this
here's my DashboarController
class DashboardController < ApplicationController
before_filter :authenticate
def index
#document = Document.new
end
end
and my DocumentsController
class DocumentsController < ApplicationController
respond_to :json, :html
def show
end
def create
#document = Document.new(params[:document])
#document.user = current_user
if #document.save
redirect_to dashboard_path, notice: 'Created!'
else
flash[:error] = 'Error!'
redirect_to dashboard_path
end
end
end
any help is appreciated :)
You are correctly redirecting on success; on failure, though, should not redirect; you need to render the template where the form was filled.
if #document.save
redirect_to dashboard_path, notice: 'Created!'
else
render 'dashboard/index'
end
You'll have to make sure that any variables needed by the index template are available in the create action of the documents_controller (you're just rendering the index template; you're not running the code from the dashboard controller's index action). Here's a excerpt from the relevant Rails Guide to clarify:
Using render with :action is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before calling render.
More at http://guides.rubyonrails.org/layouts_and_rendering.html#using-render