I'm trying to do something fairly simple but I'm not sure the rails way to do it. At its simplest, I have an index page where you can sign up for a mailing list.
I'm trying to set it up so that you can add yourself to the mailing list from the index page without ever seeing the mailing list views. I can submit the data properly using something like:
= form_for #mailing_list, :remote => true do |form|
= if #mailing_list.errors.any?
%ul
= #mailing_list.errors.full_messages.each do |message|
%li
= message
.field
= form.label :email, 'Your email'
= form.text_field :email
= form.submit "Add to Mailing List"
With the controller:
def create
#mailing_list = MailingList.new(params[:mailing_list])
if #mailing_list.save
redirect_to(:root, :notice => 'Mailing list was successfully created.')
else
? How do I return the errors ?
end
end
But I am unable to get the errors back (ie. Email not valid, etc.). Is there a better way to do what I'm attempting? I would just like to be able to call and respond to actions of the MailingList controller from the index page view...
I believe that you are wanting a form that will add someone to a Mailing list without leaving that page.
Better? Hmmm.. Well, I'll tell you what I do and you can decide what you like.
I would use respond_to in the controller to differentiate between the standard html call and the remote js call. Then, I would handle the page changes in the view. I like keeping the display in the views.
Controller:
def create
#mailing_list = MailingList.new(params[:mailing_list])
if #mailing_list.save
respond_to do |format|
format.html { redirect_to(:root, :notice => 'Mailing list was successfully created.') }
format.js { render }
end
else
respond_to do |format|
format.html { render }
format.js { render :errors }
end
end
end
create.js.erb
$('#errors').html('').hide();
$('form').html('Mailing list was successfully created.'); // needs a better element
errors.js.erb
$('#errors').html('<%= escape_javascript(#mailing_list.errors.full_messages.collect { |msg| content_tag :li, msg }.join().html_safe) %>').show();
You can do something with the errors object on #mailing_list, e.g.
flash.now[:error] = #mailing_list.errors.full_messages
Related
I have to ask about something that probably no one uses anymore. I want to display flash[:notice] after successfully AJAX action. I'm aware of this and that one and even this gist but none of them fit my example:
#controller code
def new
#registrant = Registrant.new
respond_to do |format|
format.html
if params[:add_patient_to_caregiver]
format.js { render partial: 'add_patient_to_caregiver' }
end
end
end
#view triggered controller#new action via AJAX
<%= link_to 'Add Patient to Caregiver', patient_to_caregiver_path(add_patient_to_caregiver: true, patient_to_caregiver: registrant.id), method: :get, remote: true %>
I want to have something like format.js { render partial: 'add_patient_to_caregiver', flash[:notice] = 'Patient Added' } to display it in a view. I've come up with a workaround:
_add_patient_to_caregiver.js.erb
$("#add-patient").html("<%= escape_javascript(render :partial => 'registrants/add_patient') %>");
$("#flash-messages").after("<div class='alert alert-success'> Patient Added </div>");
And flash message shows up but there are no close button there. Is there any better way to do so? or how to add close button to that message so that the whole page doesn't reload when it is pressed?
So, I'm having Events model which has_many Questions. Relation is the same as in Post->Comment. I've tried to implement some Ajax for Questions, but it seems like I'm missing something, because View doesn't updates without refreshing the page. The same problem with delete method.
Here's my question_controller.rb:
def create
#question = #event.questions.create(question_params)
#question.user_id = current_user.id if current_user
if #question.save
respond_to do |format|
format.html { redirect_to event_path(#event) }
format.js # render questions/create.js.erb
end
else
render 'events/show'
end
end
Question _form.haml:
= simple_form_for [#event, #event.questions.new], remote: true do |f|
= f.input :content, label: 'Your question:', id: 'question_content'
= f.submit class: 'submit_btn'
Question partial _question.haml:
%h4
= question.content
This is how it looks in Events show.haml:
%section#question_section
%h1 Questions:
#questions
= render #event.questions
#question-form
%h1 Submit a question:
= render 'questions/form'
And create.js.erb file:
$('#questions').append("<%= j render partial: #question %>");
$('#question_content').val('');
I've tried few different tutorials, but always had the same problem. View updates only after refreshment. Also it is my second post on Stackoverflow so would be grateful for any suggestions if something is wrong with it.
EDIT 1: mostly I've been following this tutorial: https://pragmaticstudio.com/blog/2015/3/18/rails-jquery-ajax
EDIT 2: create.js.erb seems not to respond, tried to test it with alerts or console log, but without any success. After triggering a button in the console having: "Processing by QuestionsController#create as JS" (so it runs a proper file, but file itself doesn't executes any code). Have no idea why that happening.
So the problem was because of HAML. Had to change my format.js line in the controller to:
formta.js { render layout: false }
Here's the thread that helped to solve this: Rails update.js.erb not executing javascript
The problem in brief: I'm working on a rails 4 app (4.1.8) and I'm trying to get flash[:notice] and flash[:alert] to show up under a form.
Two controllers: landingpage_controller and contacts_controller. The landingpage_controller serves a static landingpage through its show action and the contacts_controller has new and create actions, to store the contacts in a db table.
On the static landingpage, a modal with id="contact-modal" contains a partial with a simple_form_for #contact (see below). Upon submittal of the form, a db-entry is not created if the fields are not all filled out and a db-entry is created if the fields are filled out. However, no flash messages are displayed.
Wanted output:
Ideally the partial would re-load without leaving/closing the modal, with either: a success message and an empty form or a alert message and the form as it was upon submittal. How do I do this?
The controller: app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def new
#contact = Contact.new
render layout: "contact"
end
def create
#contact = Contact.new
respond_to do |format|
if #contact.save
flash[:notice] = "Success"
format.js
else
flash[:alert] = "Error"
format.js
end
end
end
private
def contact_params
params.require(:contact).permit(:email, :structure, :message_content)
end
end
The form: app/views/contacts/_new.html.haml
= simple_form_for #contact, html: { id: "contact-form"} do |c|
= c.input :email
= c.input :structure
= c.input :message_content
= c.button :submit
.messages-container
= if flash[:notice]
%p
= flash[:notice]
= if flash[:alert]
%p
= flash[:alert]
Routes:
resources :contacts, only: [:new, :create]
I'm aware that a partial reload probably involves AJAX. I've read several StackOverflow questions on this but have not been able to figure it out. See here, here and these two blog-posts: jetthoughts, ericlondon.
Your help is very much appreciated
There are several problems in your code:
views, that start with underscore are called partials and are not full actions, but just parts of reusable view code (you don't redirect to them, instead you use render since you usually don't want a full page reload.
1.1 Rename your _new.html.haml to _form.html.haml
2.1 Create a new view new.html.erb(I guess you have that already, otherwise your new action might not work properly) with content = render 'form'
From what I understand you don't want the modal to close, just to render a form after successful submission or if there is an error.
In that case:
1.create a create.js.erb file in your views/contacts folder
create.js.erb
$("#your_modal_id").html("<%= j( render 'form') %>")
2. change your create action
def create
#contact = Contact.new(contact_params)
respond_to do |format|
if #contact.save
flash[:notice] = "Success"
format.js
else
flash[:alert] = "Error"
format.js
end
end
end
to your form add remote: true
WARNING: This will leave your form filled in even if it is successful.
More about this topic see:
http://guides.rubyonrails.org/v4.1.8/working_with_javascript_in_rails.html#form-for
Hope it helps, and I hope I didn't forget anything
All, I have two dropdown boxes, which are populated from two different database tables and a form with a single submit button. My goal is to concatenate the two values upon form submit and write the single value back to the database into the form associated with the model.
More simply: two dropboxes allowing to select ['red','green','blue'] and ['dog','cat']. The user selects 'red' and 'cat', and the submit button creates a new record 'red-cat' (under the blogname model) as a result.
ENTIRE Form (new.html.erb) code:
<%= select("subdomainw1", "blognamew1", Subdomainw1.order("blognamew1 ASC").collect {|p| [ p.blognamew1 ] }, {:prompt => 'Select Adjective'}) %>
<%= select("subdomainw2", "blognamew2", Subdomainw2.order("blognamew2 ASC").collect {|p| [ p.blognamew2 ] }, {:prompt => 'Select Noun'}) %>
<%= simple_form_for (#blogname) do |f| %>
<%= f.button :submit %>
<% end %>
with the associated controller def create being:
def create
#blogname = Blogname.new(params[:blogname])
respond_to do |format|
#blogname.blogname = ?? THIS SHOULD BE A CONCATENATION OF THE VALUES FROM ABOVE SELECTS
if #blogname.save
format.html { redirect_to #blogname, notice: 'Blog was successfully created.' }
else
format.html { render action: "new" }
end
end
end
Any ideas here?
There are a lot of ways to do this, the Rails way would be to do it in your model and keep your controllers skinny.
I think the most common way in rails you'll see this done is a callback. So, for this example you could set up a before_validation (or perhaps before_create if you don't want it to be changed if the blog is edited) call back in your mode, and assign your blogname from the two other attributes.
model.rb
before_validation :generate_blogname
def generate_blogname
self.blogname ||= "#{blognamew1}-#{blognamew2}".parameterize
end
Then in your controller:
controller.rb
def create
#blogname = Blogname.new(params[:blogname])
respond_to do |format|
if #blogname.save
format.html { redirect_to #blogname, notice: 'Blog was successfully created.' }
else
format.html { render action: "new" }
end
end
end
The parameterize method will make this work for subdomains by taking out special characters. The model shouldn't probably be called blogname, it should probably be a table blog with an attribute of name. So #blog = Blog.new, then #blog.name = "Two Subdomain Values"
I'm using Ruby on Rails 2.3.8 and I've got a registration form in which I receive a parameter as follows: /registration/4, which 4 is the id of a user who recommended the user that is about to register in the website.
The problem is that if the validation fails when the user submits the registation (the form renders to the controller users, action create_particular) the site will redirect to /users/create_particular, and therefore I lose the parameter with value 4 that I had before. Besides, I want the user to stay at the same url, which is /registration/4
How can I do that?
Then you should rewrite your create method. You should use redirect_to :back instead of render :action
UPD
def new
#word = Word.new(params[:word])
#word.valid? if params[:word]
end
def create
#word = Word.new(params[:word])
if #word.save
redirect_to #word
else
redirect_to new_word_path(:word => params[:word] )
end
end
Looks quite dirty, but this is just a scratch
UPD 2
This is really not the best solution, but it works
# routes.rb
match 'words/new' => 'words#create', :via => :post, :as => :create_word
# words_controller
def new
#word = Word.new
end
def create
#word = Word.new(params[:word])
respond_to do |format|
if #word.save
format.html { redirect_to(#word, :notice => 'Word was successfully created.') }
else
format.html { render :action => "new" }
end
end
end
# views/words/new.html.erb
<%= form_for(#word, :url => create_word_path) do |f| %>
...
<% end %>
Submit to the current URI (e.g. action=""). When the submission is valid, redirect. POST->Redirect->GET is a good habit.
From the top of my head:
Edit your controller (registrations_controller.rb file). Create method by default contains following piece of code:
if #registration.save
format.html { }
format.xml { }
else
format.html { }
format.xml { }
end
Add redirect_to (:back) between brackets to else format.html{}
Ok I solved the problem by doing the following:
1) I created two routes with the same path, but with different conditions method (one it's post and the other one is set to get)
2) I changed the form in order to post to the POST action defined above
3) I added render => :my_action when the validation fails
So that's pretty much it.
Thanks anyway for all your help.
Hidden field. That user ID param has a name by which you extract it in your controller, right? So just put that value in a hidden field of the same name, then it will survive a round-trip.
For example:
<%= hidden_field_tag :referring_user_id, params[:referring_user_id] %>