Rails, triggering custom action on link - javascript

I'm trying to render an edit form when someone clicks on an object in a list.
I made a test action in my controller like this:
def test
respond_to do |format|
format.js
end
end
In my view I made a link like this:
<%= link_to image_tag('icons/edit3.png'),
:remote => true,
:controller => :aliens,
:id => alien.expansion.id,
:ph_id => alien.id,
:action => :test
%>
and in my test.js.erb
console.log('testing');
I also made a custom route
get 'expansions/:id/aliens/:ph_id/test' => 'aliens#test', as: :test
This works great. Everytime I click on an object it prints out in the console.
The problem is that I want the .js.erb to render the form. BUT, if I add this code to the js:
$('.dialog__content').append('<%= j render :partial => 'editform', :formats => :html %>');
or
$('.dialog__content').html("<%= j render(#editform) %>'");
or
$('.dialog__content').html("<%= escape_javascript (render partial: 'editform') %>");
It returns GET "My path" 404 (Not Found)
And If I add variables to my action like this:
def test
#aliens = Alien.all
#expansions = Expansion.all
#expansion = Expansion.find(params[:expansion_id])
#alien = #aliens.find(params[:id])
respond_to do |format|
format.js
end
end
It also returns: GET "My path" 404 (Not Found)
What should I do?
Thanks.
Update:
My editform partial,
Seems like the variables is the problem. I tried rendering a partial with only html in it, and that works fine.
<div class="hidden_form form_holder">
<%=form_for [#expansion, #alien], :remote => true, :html => {:class => "add edit", :multipart => true } do |f| %>
<h2>Rediger Alien </h2>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :difficulty %>
<%= f.select :difficulty, ['Beginner', 'Intermediate', 'Hard']%>
<%= f.label :tokens %>
<%= f.number_field :tokens %>
<div class="clearfix">
<div class="byside">
<%= f.check_box :gamesetup %>
<%= f.label :gamesetup, :class => 'check'%>
</div>
<div class="byside">
<%= f.file_field :avatar %>
</div>
</div>
<%= f.submit %>
<% end %>
</div>

Related

How to display flash messages, on successful ajax, at the top of my page, without refreshing?

My bookmarks index page is essentially a single page application. When I submit the form for a new bookmark at the bottom of my page, I want the page to not have to refresh and display "Bookmark successfully created!" in the form of a flash message at the top of the page.
In my application.html.erb file, I am rendering flash messages:
<!DOCTYPE html>
<html>
<head>
<title>Text Me Later</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= render partial: 'layouts/nav' %>
<% flash.each do |key, value| %>
<% if key == "notice" %>
<%= content_tag :div, value, class: "text-center alert alert-warning" %>
<% elsif key == "alert" %>
<%= content_tag :div, value, class: "text-center alert alert-danger" %>
<% else %>
<%= content_tag :div, value, class: "text-center alert alert-success" %>
<% end %>
<% end %>
<div class="container">
<%= yield %>
<%= debug(params) if Rails.env.development? %>
</body>
</html>
The create method in my bookmarks_controller:
def create
#bookmark = Bookmark.new bookmark_params
#bookmark.user_id = current_user.id
respond_to do |format|
if #bookmark.save
flash[:notice] = 'Bookmark was successfully created.'
format.html {
redirect_to user_bookmarks_path
}
format.json {
render json: #bookmark,
status: :created,
location: #bookmark
}
format.js {}
else
flash[:error] = "Bookmark could not be created."
format.html {
render :index
}
format.json {
render json: #bookmark.errors.full_messages
}
format.js {}
end
end
end
My bookmarks index.html.erbfile:
<h2>All of <%= current_user.first_name %>'s Bookmarks</h2>
<ul id="all-bookmarks">
<% #bookmarks.each do |bookmark| %>
<li class="bookmark-div">
<div><%= bookmark.title %></div>
<div><%= bookmark.image %></div>
<div><%= bookmark.description %></div>
<div><%= bookmark.location %></div>
<div><%= bookmark.time %></div>
<div><%= bookmark.date %></div>
<div><%= bookmark.created_at %></div>
<div><%= bookmark.updated_at %></div>
<div><%= bookmark.url %></div>
<div><%= link_to "Edit", [:edit, bookmark]%></div>
<div><%= link_to "Delete Bookmark", bookmark, :method => :delete, confirm: 'are you sure?'%></div>
<div><%= link_to "Add as a reminder" %></div>
</li>
<% end %>
</ul>
<h2>Add a bookmark below:</h2>
<div id="post-new-bookmark">
<%= simple_form_for [#user, #bookmark], :method => :post, remote: true do |f| %>
<% if #bookmark.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#bookmark.errors.count, "error") %> prohibited this post from being saved:</h2>
<% end %>
<%= f.input :title %>
<%= f.input :image %>
<%= f.input :description %>
<%= f.input :location %>
<%= f.input :date %>
<%= f.button :submit %>
<% end %>
</div>
create.js.erb:
$("<%= escape_javascript(flash[:notice]) %>").appendTo("#flash-notice")
$("<%= escape_javascript render(:partial => 'bookmarks/cbookmark', :locals => { :bookmark => #bookmark }) %>").appendTo("#all-bookmarks")
My question is: Why is the flash message on successful bookmark creation not displaying at the top of the page right after a successful creation? Shouldn't the flash message handling in my application.html.erbtake care of it? Could it be due to a syntax error in my bookmark controller?
I also have a question about flash.now vs flash. Is that relevant in this case since the bookmark submission is an AJAX action?
form of a flash message
Ce ne pas possible avec le flash de Rails
--
The flash forms part of the session cookie that Rails populates between actions. This has been notoriously difficult to parse with Ajax, and indeed remains a difficult pattern to implement (how can Rails repopulate the session when your browser hasn't been refreshed).
The way to go about it is to pass the value through your ajax method, using flash.now. Good ref here (I wrote about it):
#app/controllers/bookmarks_controller.rb
class BookmarksController < ApplicationController
def create
#bookmark = Bookmark.new bookmark_params
#bookmark.user_id = current_user.id
respond_to do |format|
if #bookmark.save
flash.now[:notice] = 'Bookmark was successfully created.'
format.html { redirect_to user_bookmarks_path }
format.json { render json: #bookmark, status: :created, location: #bookmark }
format.js
else
flash.now[:error] = "Bookmark could not be created."
format.html { render :index }
format.json { render json: #bookmark.errors.full_messages }
format.js
end
end
end
end
Using flash.now should allow you to populate the flash through Ajax accordingly:
#app/views/bookmarks/create.js.erb
$("<%=j flash.now[:notice] %>").appendTo("#flash-notice")

Rails ajax first request not showing up unless I refresh the page

I have a view that has a form to create a new post using Ajax, and it also renders all the posts and adds the newly added post to them. The problem is when I post the very first post, the page does not show it unless I refresh, then if I refresh it shows up and when I add more posts Ajax works fine.
Here is the view index.html.erb :
<%= link_to('Logout', destroy_user_session_path, :method => :delete) %>
<%= link_to 'Edit my account', edit_user_registration_path %>
<%= form_tag search_posts_path, method: :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", name: nil %>
<% end %>
<b> Study requests </b>
<%= form_for(#post, remote: true) do |f| %>
<%=f.label :Course_name %>
<%=f.select :course_name, options_for_select(course_names) %><br/>
<%=f.label :Course_number %>
<%=f.select :course_number, options_for_select(course_numbers) %> <br/>
<%=f.submit %>
<% end %>
<%= render #posts %>
The partial is _post.html.erb :
div id="post">
<%= post.user_name%>
</div>
Controller :
def index
#posts = Post.all.order('id DESC')
#post = Post.new
end
def create
#post = current_user.posts.build(post_params)
#post.save
respond_to do |format|
format.html { redirect_to #post, notice: "Study request successfully added" }
format.js {}
format.json { render json: #post, status: :created, location: #post }
end
end
And finally my create.js.erb :
$("<%= escape_javascript(render #post) %>").prependTo("#post");
I got it, I only needed to add a new div around my partial rendering like this :
<ul id="container">
<%= render #posts %>
</ul>
And change the create.js to append to this div

Rails - AJAX to for new/create action

I've got a timeline with events partials on it so that you can CRUD events directly on the timeline page. I've got it working so that you can delete an event, and the delete partial refreshes along with the timeline, without the page refreshing.
But I can't get it working for a new event, or to edit one. Please can someone help me figure out where I am going wrong? Thanks!
I've put the code for a new event here, as I'm sure between the new and delete, I can work out how to sort the editing.
timelines/show:
<div id="show-timeline">
<%= render :partial => "show_timeline" %>
</div>
<div id="my-timeline-box">
<%= render :partial => "my_timeline" %>
</div>
<div id="new-event">
<%= render :partial => "new_event", :locals => { :event => Event.new(:timeline_id=>#timeline.id) }, :remote => true %>
</div>
timelines/_new_event.html.erb:
<%= form_for(event) do |f| %>
<% if event.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(event.errors.count, "error") %> prohibited this event from being saved:</h2>
<ul>
<% event.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%=f.hidden_field 'timeline_id', :value => current_user.timeline.id %>
<div class="field">
<%= f.label :date %><br />
<%= f.date_select :start_date, :order => [:day, :month, :year], :start_year => 1800 %>
</div>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :headline, :size => 50 %>
</div>
<div class="field">
<%= f.label :event_description %><br />
<%= f.text_area :text, :size => "47x4" %>
</div>
<%= check_box_tag "blockCheck", :value => "1", :checked => false %>
<div class="field" id="media_box">
<%= f.label :media %> <span>Please paste a URL here</span><br />
<%= f.text_field :media, :size => 50 %>
</div>
<div class="field">
<%= f.label :media_description %><br />
<%= f.text_area :caption, :size => "47x3" %>
</div>
<div class="actions">
<%= f.submit 'Create Event', :class => "btn btn-success" %>
</div>
<% end %>
events/create.js.erb:
$('#new-event').html('<%= escape_javascript( render :partial => "/timelines/new_event", :locals => { :event => Event.new(:timeline_id=>#timeline.id) } ) %>');
$('.notice').html("<p>Event was successfully created.</p>");
$('.notice').show(300);
$('#my-timeline-box').html('<%= escape_javascript( render :partial => "/timelines/my_timeline" ) %>');
$('#show-timeline').html('<%= escape_javascript( render :partial => "/timelines/show_timeline" ) %>');
events controller:
def new
#event = Event.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #event }
format.js
end
end
def create
#event = Event.new(params[:event])
respond_to do |format|
if #event.save
format.html { redirect_to #event.timeline, notice: 'Event was successfully created.' }
format.json { render json: #event, status: :created, location: #event }
format.js
else
format.html { render action: "new" }
format.json { render json: #event.errors, status: :unprocessable_entity }
format.js
end
end
end
The :remote => true option on render :partial in the timelines/show view is not required.
Instead the form_for in _new_event.html.erb should have the options :remote (this makes the form submit via ajax) and :format (this requests the response be in JavaScript), e.g.:
<%= form_for event, :remote => true, :format => :js do |f| %>

How do I grab a comments class after a successful ajax form submit then display it with out page refresh?

I want to get ".comment_container" for the post just made and place it after the last comment.
Each comment and it's related content is stored in a ".comment_container" class.
The code below does what I need but not 100%. Rather than append the word TEST I want to append the new comment_contaner holding the comment just posted.
I've been cracking at this all day and this is how far I've come. I would appreciate some solutions with examples if possible.
JQuery:
$('#new_comment').on('ajax:success', function(){
$(this).parent('.post_content').find('.comment_container:last').after("TEST");
});
<% sleep 1 %>
HTML:
<div class="postHolder">
<nav class="micropostOptions">
<ul class="postMenu">
<li class="deletePost"><%= link_to content_tag(:span, "Delete post"), m, :method => :delete, :confirm => "Are you sure?", :title => m.content, :class => "message_delete" %>
</li>
<li class="disableCommenting"><%= link_to content_tag(:span, "Pause commenting"), "2" %></li>
<li class="blockCommenter"><%= link_to content_tag(:span, "Block commenter"), "3" %></li>
<li class="openInNewWindow"><%= link_to content_tag(:span, "Open in new window"), "4" %></li>
<li class="reportAbuse"><%= link_to content_tag(:span, "Report abuse"), "5" %></li>
</ul>
</nav>
<%= link_to image_tag(default_photo_for_current_user, :class => "poster_photo"), current_users_username %>
<div class="post_content">
<div class="post_container">
<div class="userNameFontStyle"><%= link_to current_users_username.capitalize, current_users_username %> -
<div class="post_time"> <%= time_ago_in_words(m.created_at) %> ago.</div> </div>
<%= simple_format h(m.content) %> </div>
<% if m.comments.any? %>
<% comments(m.id).each do |comment| %>
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(comment), :class => "commenter_photo"), commenter(comment.user_id).username %>
<div class="commenter_content"> <div class="userNameFontStyle"><%= link_to commenter(comment.user_id).username.capitalize, commenter(comment.user_id).username %> - <%= simple_format h(comment.content) %> </div>
</div><div class="comment_post_time"> <%= time_ago_in_words(comment.created_at) %> ago. </div>
</div>
<% end %>
<% end %>
<% if logged_in? %>
<%= form_for #comment, :remote => true, :html => {:class => "new_comment} do |f| %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<%= f.hidden_field :micropost_id, :value => m.id %>
<%= f.text_area :content, :placeholder => 'Post a comment...', :class => "comment_box", :rows => 0, :columns => 0 %>
<div class="commentButtons">
<%= f.submit 'Post it', :class => "commentButton" %>
<div class="cancelButton"> Cancel </div>
</div>
<% end %>
<% end %>
</div>
</div>
Comments controller:
class CommentsController < ApplicationController
def create
#comment = Micropost.find(params[:comment][:micropost_id]).comments.build(params[:comment])
respond_to do |format|
if #comment.save
unless params[:comment][:recipient].blank? # this will be blank when current user is commenting/replying on their own wall
recipient = User.find(params[:comment][:recipient])
UserMailer.new_wall_post_comment_notification(recipient, current_user).deliver if recipient.email_notification == 1
end
format.js { render :post_comment }
else
format.js { render :form_errors }
end
end
end
end
Comment partial:
<div class="comment_container">
<%= link_to image_tag(default_photo_for_commenter(#comment), :class => "commenter_photo"), commenter(#comment.user_id).username %>
<div class="commenter_content">
<div class="userNameFontStyle"><%= link_to commenter(#comment.user_id).username.capitalize, commenter(#comment.user_id).username %> - <%= simple_format h(#comment.content) %>
</div>
</div>
<div class="comment_post_time">
<%= time_ago_in_words(#comment.created_at) %> ago.
</div>
</div>
Seems to be working apart from 1 minor issue. Let's say I post 4 comment... 1 after each other. First comment 1, second 2, third 3 and fourth 4.. e.g. 1, 2, 3 and 4 the result I get is this:
I have a feeling it's something to do with some kind of reset needing to be done after each comment is left. After refreshing the comments display as expected. 1, 2, 3 and 4. Any thoughts?
Kind regards.
You should make the partial for rendering your Comments (I guess it should be the /views/comments/_comment.html.erb).
Then just replace:
.after("TEST");
with:
.after("<%= j render #comment %>");
This along with the advice from jdoe fixed my issue
$('.new_comment').off().on('ajax:success', function(e){
e.preventDefault();
$(this).parent('.post_content').find('.comment_container:last').after("<%= j render 'comments/partials/comment' %>");
$('#comment_content').removeClass("comment_box_focused").addClass("comment_box");
$(".commentButtons").removeClass("displayButtons");
$('#comment_content').val("");
<% sleep 1 %>
});

rails not making the link between dynamically added nested form and parent

I've got a form 'tasks' and I am dynamically adding a child 'steps' form.
The 'steps' is added through a javascript call to render('steps/form').
The form loads fine, but when submitting the tasks form, the added step is not put into the database.
I assume this is because I'm not linking the two forms together, but I'm not entirely sure.
My code is
Tasks/new.html.erb
<%= form_for #task, :html=>{:multipart=>true} do |f| %>
<%= f.label :task_name %>
<%= f.text_field :task_name %>
<%= link_to "Add Step", #step, :remote=>true, :class=>'addStep %>
<%= f.submit %>
<% end %>
<% content_for(:js) do %>
$('a.addStep').click(function(){
$('div#newStep').append("<%= escape_javascript(render('steps/form'))%>");
});
<% end %>
the steps/_form.html.erb is
<p class="fields">
<%= fields_for :steps do |builder| %>
<%= builder.label :title %>
<%= builder.text_field :title %>
<% end %>
I believe the problem is that i'm not passing 'f' or 'task' into the 'step' form, but I couldn't figure out how to do that.
Try something like this:
<%= render :partial => 'steps/form',
:locals => {:form => f} %>
Hope this helps.
Edit- 1
Do as follows:
<%= form_for #task, :html=>{:multipart=>true} do |f| %>
<%= f.label :task_name %>
<%= f.text_field :task_name %>
<div style="display:none;" id="steps_form">
<%= render :partial => 'steps/form',
:locals => {:form => f} %>
</div>
<%= link_to "Add Step", #step, :onClick=>"js_function_to_change_display_property()", :class=>'addStep' %>
<%= f.submit %>
<% end %>
then you can use simple javascript to view the steps form by changing the display property of steps_form.
You might have to update the params in your parent controller to include the attributes of the child. e.g.
controllers/task_controller.rb
Class TasksController < ApplicationController
...
def task_params
params.require(:task).permit :name, :description ,
steps_attributes: [:step, :step_description, :due_date]
end
end
models/task.rb
Class Task < ActiveRecord::Base
has_many :steps
accepts_nested_attributes_for :steps
end
models/step.rb
Class Step < ActiveRecord::Base
belongs_to :task
end

Categories