I'm new in Rails. I try to make a list of groups (/groups) where I want to have edit and delete option in each row. Editing should be implemented by modal because Group has only one attribute - name. So I don't want to open /groups/number/edit.
My problem is: I don't know how to bind chosen group with form_for. Maybe it isn't good approach indeed.
Modal is displayed, but the name field is blank. When I used debug for #group is blank too. I don't know why.
Here is my code(single group row):
<li id="group-<%= group.id %>" class="list-group-item">
<span class="group-name"><%= group.name %></span>
<%= link_to edit_group_path(group.id), "data-toggle" => "modal", "data-target" => "#myModal", :class => "edit-option btn" do %>
<i class="fa fa-pencil-square-o fa-2x" ></i>
<% end %>
<%= link_to group, method: :delete, data: { confirm: "Na pewno chcesz usunąć tę grupę?" }, :class => "delete-option btn btn-danger" do %>
<i class="fa fa-trash-o" > usuń</i>
<% end %>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Zmień nazwę grupy</h4>
</div>
<%= form_for(#group) do |f| %>
<div class="modal-body">
<%= debug #group %>
<p>
<%= f.label :name, "Nazwa" %>
<%= f.text_field :name, class: 'form-control'%>
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
<%= f.submit "Zapisz zmiany", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
Controller
def edit
#group = current_user.groups.find_by(id: params[:id])
end
def update
#group = current_user.groups.find_by(id: params[:id])
if #group.update_attributes(group_params)
flash[:success] = "Nazwa grupy została zmieniona"
redirect_to groups_path
else
redirect_to groups_path
end
end
I will assume that the answer to my question above is a yes, and so, I'll just continue to answer.
First thing: You don't want to be repeating different Modals for each group, you want only a single Modal to be used by all the groups.
Second thing: You are very correct with the idea of wanting to send the group.id to the edit method in your controller, for it to return that group back into your Modal
However, what is wrong is how you are trying to achieve this.
<%= link_to edit_group_path(group.id), "data-toggle" => "modal", "data-target" => "#myModal", :class => "edit-option btn" do %>
You are telling your link to do two things when clicked: (1) go to edit path (2) open modal. Which one will take more importance? Right now, it is the modal that is opening, and not the edit path working, which means that you are not getting to the controller at all, so accounting for why your #group is blank.
To achieve this, you will have to tell your link to do only one thing, and when that is successful, do the other.
What I'll advice is to use Ajax (by setting remote: true) on your link to go to the controller, and then open the modal on response.
Here is a breakdown of the steps:
1.Set remote: true to make the call with Ajax
<%= link_to edit_group_path(group.id), remote: true %>
2.Tell controller action (in this case, the edit action) to respond to js
def edit
#group = current_user.groups.find_by(id: params[:id])
format.js
end
Prepare an edit.js.erb file to handle the response (this will be in the same directory which your other view files are)
Populate the form with the #group from inside the response
Put the populated form in the modal
Use Javascript to show the modal
$('.modal-title').html("Edit Group")
$('.modal-body').html("<%= escape_javascript( render partial: 'form', locals: {group: #group} ) %>")
$('#myModal').modal()
As simple and as direct as that. Hope this helps a lot.
Related
I´m working to generate a PDF file with an option, this option makes visible a logo in the final PDF, I´m new in this and can´t hit the right answer
I made a plain check_box and then tried to catch a parameter, but this don´t work: <%= check_box_tag :logoless, "true", true %>
<a href="<%= pcf_generator_path(#legal_vacation, logoless: :logoless )%>" data-toggle="tooltip" data-placement="bottom"
title="Comprobante de Feriado"class="btn btn-primary" role="button" aria-pressed="true" target= '_blank'>
<%= "PCF" %></a>```
I want to be able to catch the value of a checkbox in url or in #legal_vacation variable (or directly if it´s possible).
http://localhost:3000/legal_vacations/pcf_generator/2?logoless=true <= like this
Finally I resolved using an attr_accessor called logoless.
Then I create a form with a check_box:
<%= form_for(#legal_vacation, url: request_document_path(id: #legal_vacation.id),
html: { method: "get" }) do |f|%>
<div class="form-row">
<div class="col-8 text-center">
<%= f.submit 'PCF', class: 'btn btn-primary'%>
</div>
<div class="col text-center">
<%= f.check_box :logoless %>
</div>
</div>
<% end %>
And in my controller I take that value to assign it in my pdf's:
def request_document
#legal_vacation= LegalVacation.find(params[:id])
vacation = LegalVacation.new(legal_vacation_params)
#logo = vacation.logoless
if params[:commit] == 'PCF'
document_type = "pcf"
end
pdf_info(document_type)
end
And that all!
Im submitting my form with checkboxes via Jquery with remote true but its not working. Its keeps rendering the html format in the controller and i can work out why.
Here is my submit button and form:
<%= button_to "Read sel", root_path, class: "btn btn-info btn-sm padlr", id: "notification-submit" %>
<%= form_tag read_selected_notifications_path, :authenticity_token => true, remote: true ,id: "notification-form" do %>
<% #notifications.each do |x| %>
<div class="notification-body flerowspb">
<div class="flerowspb" style="width:80%">
<div class="notif-check flecolcen">
<%= check_box_tag "read_notif[]", value="#{x.id}" %>
</div>
<div class="notif-details ">
<div class="notif-time flerowspb">
<% if !x.viewed %>
<span class="glow"> New <%= x.notification_type.capitalize %></span>
<% else %>
<span><span class="text-grey"> New <%= x.notification_type.capitalize %></span></span>
<% end %>
<span class="text-grey font-small"> <%= time_ago_in_words(x.created_at) %> ago</span>
</div>
<div class="notif-body font-medium text-grey">
<span class="text-blue"><%= link_to x.sender.username, profile_path(x.sender) %> </span> <%= x.title %> <br>
Click <span class="text-blue"><%= link_to "Here", entry_path(x.entry_id, notification_id: x.id) %> </span> to view it
</div>
</div>
</div>
<div class="notif-image">
<%= image_tag x.entry.image.small_thumb %>
</div>
</div>
<% end %>
<% end %>
So there is no actual submit button for the form as i want the button above the form not below it like this,
I understand i have to add :authenticity_token => true as rails doesnt add this to form_tag with remote: true
Here is my controller:
def read_selected
Notification.read_selected(current_user.id, params[:read_notif])
respond_to do |format|
format.html{
flash[:success] = "Selected notifications marked as read"
redirect_to notifications_path
}
format.js{
render 'notifications/jserb/read_selected'
}
end
end
Here is the js code:
$(document).on('turbolinks:load', function(){
if (window.location.href.match(/\/notifications/)) {
$('#notification-submit').on('click', function(e){
console.log('oisdjfilds');
e.preventDefault();
$('#notification-form').submit();
});
}
});
EDIT: I added in a submit button at the bottom of the form and it works as it should do, So it something to do with the way i'm submitting the form
I assume you're using Rails 5, since there is such an inconsistency in its behavior. Please, check out the issue
As far as I understand the quick solution for your problem is going to be:
Get the form HTML element:
form = document.getElementById('notification-form');
or
form = $('#notification-form')[0]
And then fire Rails submit:
Rails.fire(form, 'submit');
or
form.dispatchEvent(new Event('submit', {bubbles: true}));
Hi there it's the third I ask you to help me on this point.
I don't know how to explain it because I read some tutorials or answers but I don't understand what can I do.
Ok I am working on an app to learn Japanese language with hiragana flashcards.
I created a feature to add a card as a favorite. When I click on a grey color heart, the heart becomes in red color and it saves in an index favs page.
The problem is when I click to add as favorite the full page is loaded and I don't want it. I just wnat have the heart object which changes of state.
I would use ajax and javascript but I don't know what can I call and which is the syntax. I have ever read http://guides.rubyonrails.org/working_with_javascript_in_rails.html
And Try to do the same but it doesn't work.
here is the favs 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
# redirect_to favs_path
# redirect_to :back
render json: #fav
end
def destroy
#fav = Fav.find(params[:id])
#fav.destroy
redirect_to :back
end
end
Above I choose to redirect as a json format but now
here is the render favorite view
<% 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 the index hiraganas view where the favs render is located
<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>
I try to call it with this javascript code but i don't where I can place it and how do I have to call the file .js.erb? (I put it in application.js for now but it doesn't communicate with the rest of my code)
application.js
$(document).ready(function() {
$('.faved-on').click(function() {
var fav = $('.faved-off')
$.ajax({
type: "POST",
url: "/hiraganas",
dataType: "json",
success: function(data) {
console.log(data);
},
error: function(jqXHR) {
console.error(jqXHR.responseText);
}
});
})
})
Help will be appreciated :).
Have you tried this: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#link-to ?
There is a simple "remote: true" to add inside your link_to code. Something like that:
<%= link_to hiragana_favs_path(hiragana), class: "add-to-favorite", method: :post, remote: true do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
Then to perform some special actions in your Coffee (JS), you could do:
$ ->
$("a.add-to-favorite").on "ajax:success", (e, data, status, xhr) ->
console.log(data)
alert "Favorite added."
And you can do the same thing for the other link_to (the :delete one).
Also I would rather use "button_to" instead of "link_to method: :post" as you did, as "link_to" should not really be used to POST data. Button_to is a simple helper that works like link_to but is replaced by a form, which is better to post data. :)
Of course you don't have to, but it'd be better this way. :)
Let me know if it worked. If not, add comments and edit your question to add more info, I'll try to help you more by editing my answer and adding more info.
I have a list of group and I want to edit a single group name via modal. I use edit.js.erb file and bootstrap modal.
There are two cases, both wrong.
First:
Using "remote: true" in Partial and link_to(in single row file)
Then modal is displaying, but after SAVE button clicked always is rendering again and never close. (I don't know why)
Second:
Delete remote:true from partial.
Then modal is displaying, I can even save the changes. But when I type wrong name (blank or too long), line "render 'edit'" from Controller crash. (error: "Missing template groups/edit, application/edit...". I think rails doesn't know about edit.js.erb then, but how to repair it?
Have you got any ideas about this situation ?
Controller
def edit
#group = current_user.groups.find_by(id: params[:id])
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end
end
def update
#group = current_user.groups.find_by(id: params[:id])
if #group.update_attributes(group_params)
flash[:success] = "Nazwa grupy została zmieniona"
redirect_to groups_path
else
render 'edit'
end
end
Partial for displaying form_for in modal
<%= form_for(#group, remote: true) do |f| %>
<div>
<%= render 'shared/error2_messages', object: f.object%>
<p>
<%= f.label :name, "Nazwa" %>
<%= f.text_field :name, class: 'form-control'%>
</p>
</div>
<%= f.submit yield(:button_name), class: "btn btn-primary" %>
<% end %>
edit.js.erb file
<% provide(:button_name, 'Zapisz zmiany') %>
$('.modal-title').html("Edytuj nazwę grupy");
$('.modal-body').html("<%= escape_javascript( render partial: 'layouts/group_data_form', locals: {group: #group} ) %>");
$('#myModal').modal();
Single row in a list
<li id="group-<%= group.id %>" class="list-group-item">
<span class="group-name"><%= group.name %></span>
<%= link_to edit_group_path(group.id), remote: true, :class => "edit-option btn" do %>
<i class="fa fa-pencil-square-o fa-2x" ></i>
<% end %>
<%= link_to group, method: :delete, data: { confirm: "Na pewno chcesz usunąć tę grupę?" }, :class => "delete-option btn btn-danger" do %>
<i class="fa fa-trash-o" > usuń</i>
<% end %>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Zmień nazwę grupy</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
</div>
</div>
</div>
</div>
This looks like a follow-up to your question of yesterday.
I won't say both your approaches are wrong, I'll say you are conbining two right approaches in such a way...
(1) since you used js to send save (with the use of remote: true on your form), all you need to do is to close the modal on successful save as will be defined from update.js.erb (just like you defined an edit.js.erb for the format.js in edit) as follow:
#update.js.erb
<% if #group.errors.empty? %>
$('.modal-body').html("");
$('#myModal').modal('hide');
$("#notice").html("Group was successfully updated.");
<% else %>
$("#notice").html("Error! Group not updated.");
<% end %>
#controller update action
def update
#group = current_user.groups.find_by(id: params[:id])
#group.update_attributes(group_params)
respond_to do |format|
format.html
format.js
end
end
What you essentially did here is to check if there is no error in the #group object(this will be true if #group got saved), then emptied your Modal and then hid it from view.
(2) When you removed remote: true you are no longer using js, so when you have a wrong name, the update does not work, and the render :edit portion of your update method kicks in. However, your edit action only specifies format.js, So what you may have to do in this case is to add format.html if you want to call with html.
def edit
#group = current_user.groups.find_by(id: params[:id])
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
format.html
end
end
Note however that this may not open your modal, it will go to the edit_group_path of your app, which is the /groups/:id/edit
UPDATE: I'm almost there! See my partial answer at the end of this question.
I've got a working form with two select dropdowns, the first for countries, the second for cities. When you select a country, an ajax request automagically gets the countries and updates the countries box.
The problem is the select dropdowns are ugly, and I can't really style them. What I want is a dropdown button, which I can use Bootstrap on to make pretty: Bootstrap Button
I don't have to change the jquery or controller logic, I just have to update my view. But I don't even know where to start. This is what I have:
<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
<%= f.select :country_obj_id, options_for_select(#countries.collect { |country|
[country.name.titleize, country.id] }, #countries.first.name), {}, { id: 'countries_select' } %>
<%= f.select :city_obj_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }, 0), {}, { id: 'cities_select' } %>
<%= f.submit "Go!" %>
<% end %>
How can I convert the selects into dropdown buttons?
UPDATE: I can now get a response back. I just don't know how to handle it to update the button.
The view has two dropdown buttons. The first is the countries, the second is the cities for the first country. I want to update the list of cities for the country that is selected:
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
<% end %>
</ul>
</div>
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #cities.each do |city| %>
<%= content_tag(:li, city.name.titleize) %>
<% end %>
</ul>
</div>
Selecting a country goes into the update_cities function, which gets the cities for the country_obj_id that is passed.
def update_cities
#cities = CityObj.where("country_obj_id = ?",
params[:country_obj_id]).order(:name)
respond_to do |format|
format.js
end
end
Then the part that i don't understand. The format.js takes me to update_cities.js.coffee, which I have not changed from my original version that worked on the select dropdown:
$("#cities_select").empty()
.append("<%= escape_javascript(render(:partial => #cities)) %>")
That ends up updating my old select dropdown, which I left in the view for now. But how can I modify the js to update my new dropdown button?
You will need a mix of Javascript with Rails:
First, you will need to print all options in Bootstrap's button format:
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Countries
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, country.name.titleize) %>
<% end %>
</ul>
</div>
Add funcionality to select an option from this dropdown:
https://stackoverflow.com/a/22000328/891807
Got it. This is the coolest thing ever. It starts out with two buttons. The first says "Select A Country," and the second says "Select A City." The second button is not active to start with, and I'll probably hide it.
The view:
<div class="dropdown" style="display:inline-block;">
<button id="country-select-btn" class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A Country
<span class="caret"></span></button>
<ul class="dropdown-menu">
<% #countries.each do |country| %>
<%= content_tag(:li, link_to(country.name.titleize, update_cities_path(country_obj_id: country.id), remote: :true)) %>
<% end %>
</ul>
</div>
<div class="dropdown" style="display:inline-block;">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Select A City
<span class="caret"></span></button>
<ul id="cities_select" class="dropdown-menu">
</ul>
</div>
The dropdown items are just links, with a route set so clicking a link goes to the controller update_cities action with a country passed:
def update_cities
#cities = CityObj.where("country_obj_id = ?",
params[:country_obj_id]).order(:name)
#country = CountryObj.find_by(id: params[:country_obj_id])
respond_to do |format|
format.js
end
end
The format.js goes into update_cities.js
$("#cities_select").empty()
.append("<%= escape_javascript(render(:partial => #cities)) %>")
$("#country-select-btn").empty()
.append("<%= escape_javascript(render(:partial => #country )) %>")
That renders two partials. _city_obj.html.erb renders a link for each of the cities, which will go to the controller's index action when clicked:
<li><%= link_to(city_obj.name.titleize, index_path(:trip => {country_obj_id: city_obj.country_obj.id, city_obj_id: city_obj.id}), id: "cities_select") %></li>
The _country_obj.html partial just updates the "Select A Country" label on the button to the name of the selected country:
<%= country_obj.name.titleize %>
Now, when you click one of the city links, the controller index action can find all the guides for that city/country, then the view will render it.
From what I understood, you want to add style to your html form using bootstrap. If this is the case then this is how you can do that:
1.Add bootstrap gem if you have not done it already following the documentation(https://github.com/twbs/bootstrap-sass)
In short, you need to add following at your Gemfile:
gem 'bootstrap-sass', '~> 3.3.5'
Add following line at your app/assets/stylesheets/application.scss so that bootstrap styles gets added at every page:
#import "bootstrap-sprockets";
#import "bootstrap";
2.Using bootstrap styles, at your ugly select tag you need to add form-control at your class name as bootstrap documentation suggests. add class: "form-control" parameter like this:
<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
<%= f.select :country_obj_id, options_for_select(#countries.collect { |country|
[country.name.titleize, country.id] }, #countries.first.name), {}, { id: 'countries_select', class: "form-control" } %>
<%= f.select :city_obj_id, options_for_select(#cities.collect { |city|
[city.name.titleize, city.id] }, 0), {}, { id: 'cities_select', class: "form-control" } %>
<%= f.submit "Go!" %>
<% end %>