I am working on a Ruby on rails project. I want to get this UI format:
I tried the below code, but not getting proper results. User can create controller dynamically from permission so the controller can be anything (User,Role,Permission etc)
Controller
def display
param = params[:role]
id=param[:id]
#permission = Role
.joins(:permissions)
.where('roles.id=?',id)
.select('permissions.*')
end
result of #permission
[#<Role id: 4, name: "index", controller: "User", created_at: "2018-08-21
06:29:47", updated_at: "2018-08-24 06:39:37">,
#<Role id: 16, name: "create", controller: : "User", created_at: "2018-08-24
07:11:08", updated_at: "2018-08-24 07:11:08">,
#<Role id: 21, name: "destroy", controller: : "User", created_at: "2018-08-
24 07:31:17", updated_at: "2018-08-24 07:31:17">,
#<Role id: 25, name: "update", controller: : "User", created_at: "2018-08-24
07:52:00", updated_at: "2018-08-24 07:52:00">,
#<Role id: 26, name: "edit", controller: : "Role", created_at: "2018-08-27
06:38:39", updated_at: "2018-08-27 06:38:39">]>
view
<%= link_to 'Create', new_permission_path %>
<br/>
<thead>
<tr>
<th width="25px"><%= "User" %></th>
</tr>
<tr>
<% #permission.each do |p| %>
<% if (p.controller== 'User') %>
<th width="25px"> <%= check_box_tag "p[]", p.id %> <%= p.name %></th>
<% end %>
<% end %>
</tr>
</thead>
I think your structure should be like below
role model
class Role < ApplicationRecord
has_many :role_permissions
has_many :permissions, through: :role_permissions, dependent: :destroy
end
permission model
class Permission < ApplicationRecord
has_many :role_permissions
has_many :roles, through: :role_permissions, dependent: :destroy
end
and the middle table between role and permissions
class RolePermission < ApplicationRecord
belongs_to :role
belongs_to :permission
end
Create data from seeds.rb
Role.create!(name: admin)
Permission.create!([
{subject_class: 'Users', action: 'create',name: 'Create a User',description: 'nil', title: "Users"},
{subject_class: 'Users', action: 'index',name: 'List users',description: 'nil', title: "Users"},
{subject_class: 'Users', action: 'update',name: 'Update User',description: 'nil', title: "Users"},
{subject_class: 'Users', action: 'destroy',name: 'Remove User',description: 'nil', title: "Users"},
{subject_class: 'Users', action: 'show',name: 'Show User',description: 'nil', title: "Users"},
Role.first << Permission.all
Subject Class is name of controller and action will be name of action.
In the view you can load all role and permissions like below, I used accordion in my view, so you might need to update view as per your need
<% roles = Role.includes(:permissions).all %>
<% uniq_controller = Permission.all.group_by { |p| p.title } %>
<div class="accordion panel-group" id="accordion2">
<% uniq_controller.each do |permission| %>
<div class="panel panel-default">
<%= link_to "##{permission.first}" ,data: {parent: "#accordion2", toggle: "collapse"} do %>
<div class="panel-heading">
<h3 class="panel-title">
<%= permission.first.gsub("_"," ") %>
</h3>
</div>
<% end %>
<div id="<%= permission.first %>" class="panel-collapse collapse">
<div class="collapse show" role="tabpanel" aria-labelledby="headingOne">
<div class="card-block">
<table>
<% permission.second.each do |cont| %>
<tr>
<td><%= cont.name %></td>
<td>
<%= f.check_box :permission_ids, {multiple: true}, cont.id, nil %></td>
</tr>
<% end %>
</table>
</div>
</div>
</div>
</div>
<% end %>
</div>
In the controller just add the permission_ids: [] in permit parameters
Related
I want to make ES aggregation on many to many activerecord model on rails but no way
My model :
class Foo < ApplicationRecord
searchkick
def search_data
{
bar: bar
}
end
has_many :bars
end
I have tried many solution but always get
{"active"=>{"doc_count_error_upper_bound"=>0, "sum_other_doc_count"=>0, "buckets"=>[]}}
The answer is add this :
def search_data
Attributes.merge(
bar_names: bar.map(&:name)
)
end
Here more about how to work with associated models, here is:
Item.rb (model):
# Relations
belongs_to :brand
## many-to-many relations between Items and Textures
has_many :item_attribute_for_textures
has_many :textures, through: :item_attribute_for_textures, :class_name => 'ItemAttribute::Texture'
# Searchkick
searchkick
def search_data
{
full_item_title: full_item_title,
brand: brand.try(:title),
texture: textures.map(&:title)
}
end
ItemController.rb:
def index
args = {}
args[:brand] = params[:brand] if params[:brand].present?
args[:texture] = params[:texture] if params[:texture].present?
query = params[:busca].presence || "*"
#items = Item.search query, where: args,
aggs: {
full_item_title: {},
brand: {},
texture: {}
}
end
and view index.html.erb:
<div class="row">
<div class="col-sm-2" style="font-size: 0.75rem">
<h5>Brands</h5>
<div>
<% #items.aggs["brand"]["buckets"].sort_by{ |b| b["key"] }.each do |bucket| %>
<div>
<% if params[:brand] == bucket["key"].to_s %>
<strong><%= bucket["key"] %></strong>
<% else %>
<%= link_to bucket["key"], request.params.merge(brand: bucket["key"]) %>
<% end %>
(<%= bucket["doc_count"] %>)
</div>
<% end %>
</div>
<hr>
<h5>Texture</h5>
<div>
<% #items.aggs["texture"]["buckets"].sort_by{ |b| b["key"] }.each do |bucket| %>
<div>
<% if params[:texture] == bucket["key"].to_s %>
<strong><%= bucket["key"] %></strong>
<% else %>
<%= link_to bucket["key"], request.params.merge(texture: bucket["key"]) %>
<% end %>
(<%= bucket["doc_count"] %>)
</div>
<% end %>
</div>
<hr>
</div>
</div>
I have a weekly time entry form currently. How can i have another time entry form on the same page ? and these two forms need be submitted separately as different records. Any help would be appreciated .
Here is my code:-
show_weeks.html.erb
<div class="table-responisve>
<% if #dates != nil %>
<table class="table-bordered">
<thead>
<tr>
<% #dates.each do |date| %>
<th><%=date.to_s+","+date.strftime("%A").to_s %> </th>
<% end %>
</thead>
<tbody>
<tr>
<% #dates.each do |date| %>
<% if #time_entry %>
<td><%= text_field_tag "#{date}", #time_entry.hour_per_day["#{date}"], class: "dates" %></td>
<% else %>
<%if date < Date.today %>
<td> <%= text_field_tag "#{date}", "", class: "dates" %> </td>
<%else %>
<td><%= text_field_tag "#{date}", "", class: "dates" if date == Date.today && Time.now.strftime("%H").to_i >= 10 %> </td>
<% end %>
<% end %>
<% end %>
</tr>
<tr>
<% if #time_entry %>
<td colspan="2"> Please Enter your Comment </td>
<td colspan="5">
<% #time_entry.comments.each do |c| %>
<p><%= text_field_tag "Comment", c.message %> </p>
<% end %>
</td>
<%else%>
<td colspan="2"> Please Enter your Comment </td>
<td colspan="5"><%= text_field_tag "Comment", "" %>
</td>
<%end%>
</tr>
</tbody>
</table>
</div>
<button type="button" class="btn btn-primary"
id="save_entries">Submit</button>
<%= form_tag save_time_entries_path, method: 'post',
id:"save_time_entries" do %>
<%= hidden_field_tag "start_date", #dates.first%>
<%= hidden_field_tag "end_date", #dates.last%>
<%= hidden_field_tag "total_hours", "" %>
<%= hidden_field_tag "project_id", #project.id %>
<%= hidden_field_tag "time_entry", "" %>
<%= hidden_field_tag "message", "" %>
<% if #time_entry%>
<%= hidden_field_tag "time_entry_detail_id", #time_entry.id %>
<% end %>
<% end %>
<script>
$("#save_entries").click(function(){
var time_entry = []
var hours = 0;
var message = document.getElementById("Comment").value;
$('.dates').each(function() {
hours += Number($(this).val());
if ($(this).val() == 0)
{
time_entry.push($(this).attr('name'),0)
}else{
time_entry.push($(this).attr('name'),$(this).val())
}
});
if (hours > 60) {
alert("Total Hours Should be equal to 60");
return false;
}
else {
$("#message").val(message);
$("#time_entry").val(time_entry);
$("#total_hours").val(hours);
$("#save_time_entries").submit();
}
})
</script>
<%end%>
you can create 2 different forms with form_for, it shouldn't be a problem
I figure out solution. Using of two submission forms on same page is bad idea. So I have create previous weeks records by using after create call back and i given default values for TimeEntryDetail. Here it creates all weeks records in background. Suppose if you skipped for 6 weeks , it'll create 6 empty records in background. Here is my working code
Modal.rb
after_create :chceck_time
def check_time
#project_mem_check= ProjectMember.where(project_id: project, member_id: user).first.created_at
#present week dates coming here |
#time_entry_check = TimeEntryDetail.where(project_id: project, user_id: user).first.created_at
if #time_entry_check.nil?
#time_entry_check=#project_mem_check
end
#last_week_start=Date.today.beginning_of_week
#last_week_end =Date.today.end_of_week
#cheking project member creation shall be less than time entry creation of that project.
if #project_mem_check <= #time_entry_check
#time_check_first=TimeEntryDetail.where(project_id: project, user_id: user).pluck(:start_date).first.to_date
#time_check_last =TimeEntryDetail.where(project_id: project, user_id: user).pluck(:start_date).last.to_date
#check first entry == last time entry
if #time_check_first==#time_check_last
pm=ProjectMember.where(project_id: project, member_id: user).first.created_at.to_date
tm=Date.today.to_date
unfilled_weeks= ((tm-pm)/7).to_i+1
unfilled_weeks.times {
#last_week_start= #last_week_start-7
#last_week_end = #last_week_end-7
#call_back_entry=TimeEntryDetail.create(start_date: (#last_week_start).to_date, end_date: (#last_week_end).to_date,
project_id: project.id, user_id: user.id, hours: 0, aasm_state: "pending", hour_per_day: "" )
#call_back_entry.comments << Comment.create(message: "Please fill the timesheet ")
}
else
#Already this user have time entries and create empty records from where he stopped.
pm=created_at.to_date #--.present time entry is coming
tm=Date.today.to_date
unfilled_weeks= ((tm-pm)/7).to_i+1
unfilled_weeks.times{
#last_week_start= #last_week_start-7
#last_week_end = #last_week_end-7
#call_back_entry=TimeEntryDetail.create(start_date: (#last_week_start).to_date, end_date: (#last_week_end).to_date,
project_id: project.id, user_id: user.id, hours: 0, aasm_state: "submitted", hour_per_day: "" )
#call_back_entry.comments << Comment.create(message: "Not yet filled this week ")
}
end
end
end
I am getting the following undefined method each error.
I am following along with the exercises on Lynda and I am stuck here. I have attempted to understand the solutions in the other questions but its still beyond my understanding. any help will be greatly appreciated.
ActionView::Template::Error (undefined method `each' for nil:NilClass):
10: <th>Pages</th>
11: <th>Actions</th>
12: </tr>
13: <% #Subjects.each do|subject| %>
14: <tr>
15: <td><%= subject.position %></td>
16: <td><%= subject.name %></td>
app/views/subjects/index.html.erb:13:in `_app_views_subjects_index_html_erb__3548269486732453408_70351994996820'
Here is the index code that is defined in models/views/subjects/index.html.erb
<div class = "subjects index">
<h2>Subjects</h2>
<%= link_to("Add New Subject",'#', :class => 'action new') %>
<table class ="listing" summary ="Subject list">
<tr class = "header">
<th> </th>
<th>Subject</th>
<th>Visible</th>
<th>Pages</th>
<th>Actions</th>
</tr>
<% #Subjects.each do|subject| %>
<tr>
<td><%= subject.position %></td>
<td><%= subject.name %></td>
<td class ="center"><%= subject.visible ? 'Yes' : 'No' %></td>
<td class = "center"><%= subject.pages.size %></td>
<td class = "action">
<%= link_to("Show", '#',:class => 'action show') %>
<%= link_to("Edit", '#' ,:class => 'action edit') %>
<%= link_to("Delete", '#',:class => 'action delete') %>
</td>
</tr>
<% end %>
</table>
</div>
Subject model is as follows:
class Subject < ActiveRecord::Base
has_many :pages
scope :visible, lambda { where(:visible => true) }
scope :invisible, lambda { where(:visible => false) }
scope :sorted, lambda { order("subjects.position ASC") }
scope :newest_first, lambda { order("subjects.created_at DESC")}
scope :search, lambda {|query|
where(["name LIKE ?", "%#{query}%"])
}
end
when i type Subject.all
irb(main):001:0> Subject.all
Subject Load (0.2ms) SELECT `subjects`.* FROM `subjects`
=> #<ActiveRecord::Relation [#<Subject id: 1, name: "Initial Subject", position: 1, visible: true, created_at: "2015-04-28 04:11:54", updated_at: "2015-04-28 04:18:58">, #<Subject id: 2, name: "Revised Subject", position: 2, visible: true, created_at: "2015-04-28 04:15:01", updated_at: "2015-04-28 04:22:12">, #<Subject id: 4, name: "Third Subject", position: 3, visible: false, created_at: "2015-04-28 04:31:04", updated_at: "2015-04-28 04:31:04">]>
Your #Subjects is uppercase so this is empty. Also please check first #subjects.present? before loop through each.
In my application, there are two classes , which have 'has_many' relationship.
And from that design, I can fetch object from my controller(*_controler.rb) and can pass successfully to my view (*.html.erb)
But on view part(*.html.erb) i can not access object's collection class...
I got following exception:
ActionView::TemplateError (You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.inject) on line #31 of app/views/student/_populate.html.erb:
Model Classes:
class Student < ActiveRecord::Base
has_many :Subject, :class_name=>"Subject"
attr_accessible :first_name, :middle_name, :last_name,
self.table_name="students"
set_primary_key :id
blahblah
end
class Subject < ActiveRecord::Base
belongs_to :Student, :foreign_key=>'student_id'
attr_accessible :student_id, :name
self.table_name="subjects"
blahblah
end
Controller:
class StudentController < ApplicationController
require "student.rb"
def populate
#pos=0
filter_query = ''
if !params[:firstName].blank?
filter_query +=" first_name='" + params[:firstName].to_s + "' and"
end
if filter_query !=''
filter_query= filter_query[0..filter_query.length-4]
#stuData= Student.find(:all, :conditions=>filter_query)
end
end
View:
populate.html.erb
<div class="header">
<div class="heading" style="float:left;width:900px;">
<% form_tag(:controller=>"student", :action=>"populate") do %>
<table>
<tr>
<td width="10"> <label> First Name:</label> </td>
<td width="40"> <%= text_field_tag('firstName') %> </td>
</tr>
</table>
<input name="submitFormName" class="form_submit" type="submit" value="Search" />
<% end %>
<div height="10"> </div>
</div>
</div>
<div class="students" style="float:left;width:1330px;">
<% if !#stuData.blank? %>
size = <%= #stuData.size %>
<% if !#stuData.nil? %>
<%= render :partial=>'populate' , :locals=>{:stuData => #stuData} %>
<% end %>
<% else %>
<div>Not found...</div>
<% end %>
</div>
_populate.html.erb
<div style="overflow-y:auto;overflow-x:scroll;">
<table >
<thead>
<th>Id</th>
<th>First Name</th>
<th>Middle Name </th>
<th>Last Name</th>
<th>Subject Name</th>
</thead>
<% stuData.each do |item| %>
<tr>
<td id="studentId"> <%= item.id %> </td>
<td id="firstNameId"> <%= item.promotion_code %> </td>
<td id="middleNameId"> </td>
<td id="lastNameId"> </td>
<td id="cityId">
<% #var1 = item.Subject %>
<% if #var1.nil? %>
<% #var1.each do |pc| %>
<%= pc.name %>
<% end %>
<% end %>
</td>
</tr>
<% end %>
</table>
</div>
I have crossed check on console:
#student = Student.find(144)
=> #<Student id: 4, first_name: "ABC", middle_name: "DEF", last_name: "GHI">
>>
?> #isNullCheck = #student.Subject.nil?
=> false
>>
?> #subList = #student.Subject
=> [#<Subject id: 5, student_id: 4, name: "Maths">, #<Subject id: 6, student_id: 4, name: "English"> ]
>>
?> #StuSub1 = #student.Subject[0]
=> #<Subject id: 5, student_id: 4, name: "Maths">
>>
?> #StuSub2 = #student.Subject[1]
=> #<Subject id: 6, student_id: 4, name: "English">
==
?> #StuSub3 = #student.Subject[2]
=> nil
>>
>> #StuSubValue1 = #student.Subject[0].value
=> Maths
>>
>> #StuSubValue2 = #student.Subject[0].value
=> English
>>
Problem:
When i will search any student details from the page(populate.html.erb), my controller will fetch the data and passed the object (#stuData) to the template(_populate.html.erb).
Template(_populate.html.erb) can print student's data.
But can not print student's subject's name. (As student has many subjects)
I have googled many things....
i think there is nothing wrong in model's design and controller part....
but i think problem might be with
page rendering or
local parameters passing to template or
collection parameter passing to template...
but i am not sure....
can any one help me in this???
Thanks in advance,
Your relationships are set up incorrectly. Variable names cannot begin with a capital letter. This article may help.
Set them up without using capitals and use plurals instead - like so:
has_many :subjects and belongs_to :student
and make sure you propagate changes through your views
I'm trying to create an inventory form that sorts the products based on their category. Ideally I'll be able to have these products listed by category, and will put in some javascript to hide/show products of a given category.
Currently, I'm having trouble wrapping my head around how to split my products up by category in my form. Here's what I currently have (modeled after Ryan Bates' Railscasts for nested attributes):
class InventoriesController < ApplicationController
def new
#title = "Take Inventory"
#vendor = ProductVendor.find(params[:product_vendor_id])
#inventory = Inventory.new()
#products = #vendor.products.active
#products.each do |product|
#inventory_line_item = #inventory.inventory_line_items.build({:product_id => product.id})
end
end
My form for a new inventory:
<%= form_for #inventory do |f| %>
<table>
<tr>
<th>Item</th>
<th>Quantity</th>
</tr>
<% f.fields_for :inventory_line_items do |builder| %>
<tr>
<td><%= builder.object.product.name %></td>
<td><%= builder.text_field(:quantity, :size => 3) %></td>
<%= builder.hidden_field :product_id %>
</tr>
<% end %>
</table>
<%= f.hidden_field(:user_id, :value => current_user.id) %>
<%= f.hidden_field(:location_id, :value => current_location.id) %>
<%= f.hidden_field(:product_vendor_id, :value => #vendor.id) %>
<%= f.submit "Submit" %>
<% end %>
So I have another model called product_category that has_many products. How do I sort and separate my products by category in the controller and form? Also, is there a way to do this using Formtastic? Thanks!
It's actually pretty simple to implement. Add a hidden field in the nest_form field with the attribute position (add this attr to your model of course) and add this to your js along with using the jquery-ui.js
$('#task_fields').sortable({
items: '.fields',
dropOnEmpty: true,
cursor: 'move',
handle: '.move',
opacity: 0.4,
scroll: true,
axis:'y',
placeholder: 'ui-state-highlight',
start: function(e, ui) {
ui.placeholder.height(ui.item.height());
},
update: function() {
$(this).children(".fields").each(function(index) {
$(this).children('input.task_position').val(index + 1);
});
}
});
here's what I have in my _form.html.haml
= f.fields_for :tasks do |t|
= t.text_field :name
= t.hidden_field :position, :class => :task_position
= t.collection_select :account_id, Account.all, :id, :full_name, :prompt => 'Assign task to...'
.button-group
%span{:class => "button icon no-text move pill"}
= t.link_to_remove "", :class => "button icon no-text remove pill"
= f.link_to_add "Add a Task", :tasks, :class => "button icon add"
This worked really well.