Update model field with button Rails - ruby-on-rails

I have a messaging system in my Rails 5 project where the Message model has an isread field to indicate whether the recipient has read the message yet or not.
I'm using a bootstrap modal to view the message and would like the message's isread field to change to true when the modal is closed.
Could someone explain how to do this from the button_tag or make the button tag call method in the controller to do it?
Something like:
message.isread = true
message.save!
to execute when the "Close" button is pressed from my view:
<div id="modal1<%= index %>" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><%= message.subject %></h4>
</div>
<div class="modal-body">
<p><%= message.content %></p>
</div>
<div class="modal-footer">
<%= button_tag "Close", :class => "btn btn-default", "data-dismiss" => "modal" %>
</div>
</div>
</div>
</div>
Thank you!

You can define a new action in your controller which update the attribute isread to true and use the button_to helper
#routes
resources :messages do
post :is_read, on: :member
end
#messages controller
def is_read
#message = Message.find(params[:id])
#message.update(isread: true)
redirect_to ...
end
#view
<%= button_to "Close", is_read_message_path %>

If you want a button click to call a method in your controller you will need to first capture the action of the button click in javascript
$(".btn-default").click(function(){
});
Then you want to do an Ajax call to the controller method
$.ajax({
url: "/message/update_is_read",
type: "POST",
data: {is_read: isRead},
success: function(resp) {
console.log(resp);
},
error: function(resp) {
console.log(resp);
},
});
then in your controller catch it with
def update_is_read
is_read = params[:is_read]
end
Make sure you make add the path to your routes
post '/messages/update_is_read', to: 'messages#update_is_read', as: '/messages/update_is_read'
You can modify the controller code to save.

Related

Modal for tr - different id index page

I have an index page with different software in a table.
I want to display additional information (in a modal) when we click on a tr.
Everything works but I have the information of a single software that appears in my modal and is the same for each tr.
I would like to display the information of each software in the corresponding modals.
My script :
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal').modal('show');
}
});
My view :
<% #nonpremium.each do |software| %>
<table>
<tr class="clickable">
<td class="hey1">
<%= link_to software_path(software), class: "no-click" do %>
<%= image_tag software.logo.url(:medium), class:"no-click"%>
<% end %>
</td>
<td class="hey3">
<h6><%= software.slogan %></h6>
<p><%= software.largeslogan %></p>
</td>
</tr>
</table>
<div class="modal fade bd-example-modal-lg" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<%= link_to software.software_name, software_path(software), class:"no-click" %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<% end %>
I tried something like this in my script, but it does not work ..
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal-<%= #software.id %>').modal('show');
}
});
Thx for you help
EDIT :
Controller/pages
class PagesController < ApplicationController
before_action :click, only: :index
def home
#softwares = Software.all.order(:cached_votes_up => :desc )
#premium = Software.includes(:user).where(users: { subscribed: true }).order("RANDOM()").limit(2)
#nonpremium = #softwares - #premium
end
def search
#softwares = Software.ransack(name_cont: params[:q]).result(distinct: true)
#categories = Category.ransack(name_cont: params[:q]).result(distinct: true)
respond_to do |format|
format.html {}
format.json {
#softwares = #softwares.limit(5)
#categories = #categories.limit(5)
}
end
end
end
EDIT 2 :
I have the desired result by putting in my table the information that I want to recover, then I put a "display: none".
<style>
td.test {
display:none;
}
</style>
<td class="test">
<span><%= software.software_description %></span>
<span><%= get_video_iframe(software.youtube_id) %></span>
</td>
Then I get the information from my table in my script:
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
var description = this.childNodes[3].innerHTML;
var name = this.childNodes[5].innerHTML;
document.getElementById("myModalName").innerHTML = name;
document.getElementById("myModalDesc").innerHTML = description;
$('#exampleModal').modal('show');
}
});
For then displayed in my modal:
...
<div class="modal-body" id="myModalName">
Name
</div>
<div class="modal-body" id="myModalDesc">
Description
</div>
...
There is probably better to do, but being a beginner is how I achieve the desired result.
However I would like to post videos in my modals.
Am I not going to overload my home page by hiding youtube videos with my display: none?
You won't be able to use erb in your script (unless this is in a script tag within your view, in which case your code should work) - better using a data attribute. For example, if you update your tr to the following:
<%= content_tag :tr, class: "clickable", data: { software_id: #software.id } do %>
# the rest of your code within the tr
<% end %>
# Equivalent of using:
# <tr class="clickable" data-software_id="<%= #software.id %>">
This attaches the relevant software_id to the tr in the DOM. You can then use the following in your script, accessing this new attribute:
$(".clickable").click(function(e) {
if (!$(e.target).hasClass('no-click')) {
$('#exampleModal-' + $(e.target).data('software_id')).modal('show');
}
});
And everything should work as desired.
Let me know how you get on or if you have any questions. Hope this helps!
Edit based on your comment:
That error you're seeing will come because #software is nil and you are, therefore, attempting to call id on nil.
It's a common error, and means to need to ensure #software is correctly set in your controller. If you post your controller code, I might be able to help with this.
Alternatively, you can 'safely' try the method, using #software&.id with newer versions of Ruby / Rails (or #software.try(:id) on older versions). However, that's not likely to be helpful here, more of a side note :)
Edit 2:
So, in your controller, you're not actually assigning the singular #software, rather the plural #softwares:
#softwares = Software.all.order(:cached_votes_up => :desc )
#premium = Software.includes(:user).where(users: { subscribed: true }).order("RANDOM()").limit(2)
#nonpremium = #softwares - #premium
Then, in your view, you're looping through #nonpremium using the local variable software. So, you can either:
assign #software in the controller if it should always use the same data in the modal
go back to the previous option, assigning a data attribute to the tr, which is what I'd recommend. Using that should work, although you'll need to alter the code to use software without the # to address the correct variable.
I.E.
<%= content_tag :tr, class: "clickable", data: { software_id: software.id } do %>
# the rest of your code within the tr
<% end %>
This ensures the script addresses the click based on the element clicked, and pulls the id directly from there, which is within the scope of your software loop.
That do it for ya?

how can I show yearly chart on buttonclick in rails

By default I show a chart for monthly data in my view using chartkick and highcharts. i have already prepared a hash for showing yearly chart but how can I show show yearly chart on buttonclick. My html:
<div class="flot-chart">
<div class="flot-chart-content" id="flot-dashboard-chart">
<%= column_chart #chart_by_month ,height: "200px",width: "900px" %>
</div>
</div>
and the button I have added is only month. I will add a chart for yearly data, but how do I show it with button click?
<div class="btn-group">
<button type="button" id="by_month" class="btn btn-xs btn-white">Monthly</button>
</div>
If I understand you, you need to implement the ajax call described in section Say goodbye to timeouts and then add the filter you want in the controller and also js functionality. Do not forget the route.
Some like:
HTML:
<div class="flot-chart">
<div class="flot-chart-content" id="flot-dashboard-chart">
<%= column_chart chart_by_period_path( period: "month") ,height: "200px",width: "900px" , id: "id_g1" %>
</div>
</div>
ROUTE:
...
get 'chart_by_period/(:period)', to: "controller#chart_by_period", as: "chart_by_period"
...
JS:
...
var g1 = Chartkick.charts["id_g1"];
$("button#refresh_graph__year_btn").on('click', function(){
g1.updateData( "/chart_by_period/year");
});
...
CONTROLLER:
def chart_by_period
if params[:period] == "month"
...
output = ....
...
elsif params[:period] == "year"
...
output = ....
...
end
render json: output
end

Append results of form submission from inside Foundation 6 reveal to outside of the modal

I have a Rails form that is inside of a Foundation 6 reveal modal.
<div class="where-i-want-to-prepend">
<p><a data-open="exampleModal1">Click me for a form</a></p>
<div class="reveal" id="exampleModal1" data-reveal>
<%= form_for :object do |f| %>
<%= f.select :attribute %>
<%= f.submit %>
<% end %>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true">×</span>
</button>
</div>
</div>
On submission of the form, I close the reveal with ajax and , and when the modal is closed, I want to prepend the submitted data to div.where-i-want-to-prepend, which is the containing div of the modal.
$('.new_object').submit (e) ->
e.preventDefault()
$this = $(this)
url = $this.attr('action')
valuesToSubmit = $this.serialize()
$.ajax url: url, type: 'post', data: valuesToSubmit, success: (data) ->
newDetails = "New Details"
$this.parents('div.reveal').on 'closed.zf.reveal', ->
$this.parents('div.where-i-want-to-prepend').prepend($(newDetails).fadeIn(2700))
$this.parents('div.reveal').foundation('close')
This submitted data can't seem to make it out of the modal, but if i do something like:
$this.parents('div.reveal').on 'closed.zf.reveal', ->
$this.parents('div.reveal').prepend($(newDetails).fadeIn(2700))
$this.parents('div.reveal').foundation('close')
The submitted data will prepend to the inside of the modal.
How do I get the submitted form data to prepend outside of the reveal modal and to the containing div?
Thanks.

bootstrap modal and rails UJS on links

I am using Rails 4 and bootstrap. When the user clicks the link, I want modal to appear, the controller action corresponding to the remote-url to be invoked, and the response to be loaded in the modal. The four data attributes I need are: data-toggle and data-target for the modal and remote: true and data-url for the rails.js ajax.
I construct the link and modal in a helper as so:
def modal(title, &block)
options = { 'data-url' => tasks_path, remote: true, 'data-toggle' => "modal", 'data-target' => '#unresolvedTasks' }
link = link_to '#', options do
content_tag(:span, nil, class: 'dom_class') + title
end
modal = render layout: "shared_resources/modal", locals: { options: options}, &block
link + modal
end
The resulting html:
<a class="" data-remote="true" data-target="#unresolvedTasks" data-toggle="modal" data-url="/tasks/1" href="#" style=""><span class="glyphicon glyphicon-plus"></span>sdfdsf sdfdsfds</a>
<div class="modal fade in" id="unresolvedTasks" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false" style="display: block;">
<div class="modal-dialog modal-sizer">
<div class="modal-content">
<div class="modal-header" style="overflow: auto;">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
</div>
<div class="loading" style="display: none;">
<img alt="Spinner" src="/assets/spinner.gif">
</div>
<div class="modal-target">
</div>
</div>
</div>
</div>
Unfortunately, when I click the link, it does not go to '/tasks/1'. Instead it goes to '/'. Why is the data-url being ignored?
You have this code in your question: link = link_to '#'
Which means that it does, in fact, link to / and not /tasks/1
In the first code block, change the link = link_to '#' to link = link_to '/tasks/1'

Add as favorite with no full page refresh

I am working on a Hiragana flashcards app.
I spend nights and days to understand how don't refresh full page when I add a flashcard (hiragana) as a favorite.
Here is the favorite controller
class FavsController < ApplicationController
def index
#favs = Fav.where(user: current_user)
end
def create
#hiragana = Hiragana.find(params[:hiragana_id])
#fav = current_user.favs.new(hiragana: #hiragana)
if not #hiragana.favs.where(user: current_user).take
#fav.save
end
render json: #fav
end
def destroy
#fav = Fav.find(params[:id])
#fav.destroy
redirect_to :back
end
end
I render json in the create method and when I click on view I add only an hash
render view favorite
<% if current_user %>
<div class="hiragana-fav">
<% if hiragana.is_faved_by(current_user) %>
<%= link_to fav_path(hiragana.is_faved_by(current_user)), method: :delete do %>
<i class="fa fa-heart faved faved-on"></i>
<% end %>
<% else %>
<%= link_to hiragana_favs_path(hiragana), method: :post do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
<% end %>
</div>
<% end %>
and it is located in hiragana render
<div class="row">
<ul class="list-inline text-center card-frame">
<li>
<div class="card">
<div class="front">
<% if current_user.try(:admin?) %>
<%= link_to hiragana_path(hiragana), class:'trash-hiragana', data: { confirm: 'Are you sure?' }, method: :delete do %>
<%= image_tag("delete-btn.png") %>
<% end %>
<% end %>
<span class="card-question img-popover" data-content="<h4 class='text-center letter-uppercase'><%= hiragana.bigletter.upcase %></h4><p class='text-center'><b><%= hiragana.midletter %></b> comme dans <b><%= hiragana.transcription %></b></p>">
<i class="fa fa-eye fa-lg"></i>
</span>
<div class="card-hiragana hiragana-<%=hiragana.bigletter.downcase.last%>">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-katakana">
<p><%= hiragana.ideo2 %></p>
</div>
<%= render 'favs/favorites', hiragana: hiragana %>
</div>
<div class="back">
<div class="col-sm-3 col-xs-4 col-md-3 containerbackcards-<%=hiragana.bigletter.downcase.last%>">
<div class="backcard-hiragana">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-bigletter">
<h4><%= hiragana.bigletter.upcase %></h4>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
When I add a card as favorite it gives me a hash like this :
{
id: 64,
user_id: 1,
hiragana_id: 4,
created_at: "2016-02-10T16:37:26.270Z",
updated_at: "2016-02-10T16:37:26.270Z"
}
I just want to have the heart grey to red as favorite, saved and not refresh the entire page. Your explainations are appreciated thank you.
In order to send the request to the controller without the page refreshing you need to use a combination of Ajax and JavaScript.
You use JavaScript to add a click listener to the .faved-on button and to trigger the Ajax request. You will also use JavaScript to prevent the default action occurring when you click the link ie. The Page Refresh
You then use Ajax to send the request to the controller and handle the response.
Your initial JavaScript code looks pretty correct, except you are missing the bit to stop the page from reloading.
See the e.preventDefault(); line below
$(document).ready(function() {
$('.faved-on').click(function(e) { //make sure to pass in the e (the event paramter)
e.preventDefault(); //this is the line you are missing
var fav = $('.faved-off')
//let your ajax handle the rest then
$.ajax({
type: "POST", url: "/hiraganas", dataType: "json",
success: function(data) {
console.log(data);
//change the color of your heart to red here
},
error: function(jqXHR) {
console.error(jqXHR.responseText);
}
});
})
})
I haven't tested your JavaScript but it looks pretty close to correct, I believe its the e.preventDefault(); bit you were missing

Resources