Relationships; Cannot get all events from DB - ruby-on-rails

My models are;
class region
has_many :cities
end
class event
belongs_to :city
end
class city
has_many :events
belongs_to :region
end
Eventcontroller
def index
#region = Region.find(params[:region_id])
#cities = #region.cities
#city = City.find(params[:city_id])
#events = #city.events
#events_by_date = #events.group_by(&:start_on)
end
Page:
region/x/cities/x/events
Shows all the events from the city.
Question: how can i show all events from all the cities on my /region/events page? I created a resources
resources :regions do
resources :events do
collection do
get 'all_events'
end
end
But how I define the "all_event" action in the eventcontroller?
I cannot do this in my eventcontroller #events = #cities.events because event belongs_to :city. Is there a solution for this?
I tried this:
controller:
#region = Region.find(1)
#events = Event.includes(:city)
#events_by_date = #events.group_by(&:published_on)
View:
%ul.property_list
- #events_by_date[date].each do |event|
%li.restaurant
%span.icon
%h5
= link_to event.title, polymorphic_path([#region, event.city.name, event])
error : undefined method `region_Assisi_event_path'

If I am understanding this correctly all you would need to do:
In your controller
def all_events
#events = Event.includes(:city)
end
Then in your view, use a block to access all the instances
#events.each do |event|
event.name
event.city.name #not sure if you have a name attribute

Related

Why does "undefined method" on null:String in Rails?

As i'm trying to show a specific data from has_many relation on a iteration
Why Rails shows undefined method for Null:String and how do I fix it?
NoMethodError (undefined method `rated' for "shop_date is not
null":String)
# controller Cast
def cast
#products = Product.all
#rating = Product.joins(:shops).where(:shops => ('shop_date is not null').rated.average(:b_rating) || 0 )
end
# Model Shop
belongs_to :product
attr_accessible :b_rating,:product_id
scope :by_participant, -> { where('shop_date is not null').order('shop_date desc') }
scope :rated, -> { where('b_rating is not null') }
def self.average_rating
by_participant.rated.average(:b_rating) || 0
end
# Model Product
Has_many :shops
I suppose, simplest way is to user group by query:
# controller
#products = Product.all
products_ids = #products.collect(&:id)
#ratings =
Shop.where(product_id: products_ids).
where('shop_date is not null').rated.
group(:product_id).
average(:b_rating)
# view
<% #products.each do |product| %>
Rating: <%= #ratings[product.id] || 0 %>
<% end %>

Rails and arrays

Here is problem :
Order object has two attributes which defined as array of string (list_of_products, quantity_of_product). Also Order has_many line_items and has_many products through line_items.
This is show_receipt action in Public controller:
def show_receipt
#order = Order.find(params[:id])
#order.sum = 0.0
#order.quantity = 0
#order.quantity_of_product = []
#order.list_of_products = []
#order.line_items.each do |item|
#product = Product.find(item.product_id)
#order.list_of_products << #product.name
#order.sum += (item.quantity*item.price).to_d
#order.quantity += item.quantity
#order.quantity_of_product << item.quantity.to_s
#product.unite = #product.unite - item.quantity
#product.save
end
#order.save
end
it works fine, when I debug(#order) in the view of show_receipt action I can see those two arrays (list_of_products and quantity_of_product). Both are NOT empty. But when I debug(#order) in the view of ../orders/#order there are two arrays but one of them (list_of_products) is empty and the other one (quantity_of_product) is NOT empty?
Here is Order class:
class Order < ActiveRecord::Base
belongs_to :customer
has_many :line_items
has_many :products, :through => :line_items
accepts_nested_attributes_for :line_items
accepts_nested_attributes_for :products
end
Any idea?

How do I update Nested Attributes in Rails without accepts_nested_attributes_for?

I'm working on a project for a class where I have a very large form with Nested Models. Here are the models that are important to the form, as well as their associations:
Course: has_many :time_blocks, has_many :tags, through: :taggings, belongs_to :institution, has_many :roles, has_many :users, through: :roles
TimeBlock: belongs_to :course
Tag: has_many :taggings
Tagging: belongs_to :tag, belongs_to :taggable_type
Institution: has_many :courses, has_many :users
Role: belongs_to :course, belongs_to :user
I am able to create the Nested Form correctly, but I can't get the Nested Models to update correctly. Here is the controller, the form is very long, but I have provided the params for the Nested Models. Note, I cleared out the values from the params, but some of the params have ID values because they exist in the db. I've also included the CoursesHelper to show the helper methods I'm using in the controller.
app/controllers/courses_controller.rb
def new
#course = current_user.courses.new
#course.institution = Institution.new
4.times { #course.tags.build }
7.times { #course.time_blocks.build }
end
def create
#course = Course.new(params[:course])
#course.institution = Institution.new(params[:institution])
filled_tags = set_tags(params[:tag])
#course.tags.build(filled_tags)
filled_time_blocks = set_time_blocks(params[:time_block])
#course.time_blocks.build(filled_time_blocks)
if #course.save
Role.create!(
user_id: current_user.id,
course_id: #course.id,
title: 'instructor'
)
redirect_to #course
else
(4 - filled_tags.count).times { #course.tags.build }
(7 - filled_time_blocks.count).times { #course.time_blocks.build }
flash.now[:errors] = #course.errors.full_messages
render :new
end
end
def edit
end
def update
filled_time_blocks = set_time_blocks(params[:time_block])
filled_time_blocks.each do |time_block|
#course.time_blocks.update_attributes(time_block)
end
filled_tags = set_tags(params[:tag])
filled_tags.each { |tag| #course.tags.update_attributes(tag) }
# #course.tags.update_attributes(filled_tags)
# #course.time_blocks.update_attributes(filled_time_blocks)
fail
if #course.update_attributes(params[:course])
redirect_to #course
else
flash.now[:errors] = #course.errors.full_messages
render :edit
end
end
app/helpers/courses_helper.rb
def set_time_blocks(entries)
result = []
days = entries[:day_of_week].reject! { |day| day.blank? }
days.each do |day|
time_block = {}
time_block[:day_of_week] = day
time_block[:start_time] = entries[day][:start_time]
time_block[:end_time] = entries[day][:end_time]
time_block[:id] = entries[day][:id]
result << time_block
end
result
end
def set_tags(entries)
[].tap do |tags|
entries.each do |entry|
tags << entry unless entry.values.all?(&:blank?)
end
end
end
def find_course
if params.include?(:id)
#course = Course.find(params[:id])
else
flash[:notice] = "Sorry, Could Not Find Course."
redirect_to current_user
end
end
TimeBlock Params
{"sun"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "mon"=>{"start_time"=>"", "end_time"=>"", "id"=>"3"}, "tue"=>{"start_time"=>"", "end_time"=>"", "id"=>"4"}, "wed"=>{"start_time"=>"", "end_time"=>"", "id"=>"5"}, "thu"=>{"start_time"=>"", "end_time"=>"", "id"=>"6"}, "fri"=>{"start_time"=>"", "end_time"=>"", "id"=>"7"}, "sat"=>{"start_time"=>"", "end_time"=>"", "id"=>""}, "day_of_week"=>[]}
Tag Params
[{"name"=>"", "id"=>"4"}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}, {"name"=>"", "id"=>""}]
If you cant make it work with accepts_nested_attributes_for then you'll have to write your own setter method(s) manually. Something like:
class Course < ActiveRecord::Base
def tag_attributes=(tags)
tags.each do |tag|
self.tags.build(tag)
end
end
end
The method name (tag_attributes= in my example) needs to match the key name that the tag params are listed under

code refactory on a small controller(thin controller fat model)

I have a controller action that is doing product listing, pagination and some filters, like category(from a dropdown), title(from a text-field), stock(from a checkbox)
This is my controller:
class ProductsController < ApplicationController
def index
#products = Product.where(active:1).where("title LIKE ?","%#{params[:title]}%")
if params[:stock]
#products=#products.where("stock = 0")
end
if params[:category]
#products=#products.where("category_id LIKE ?","#{params[:category]}")
end
#products= #products.paginate(:page => params[:page])
#categories= Category.all
end
And my model is:
class Product < ActiveRecord::Base
belongs_to :category
...some validations...
end
What could I change in order that my controller would become thinner? Thanks
Model
class Product < ActiveRecord:::Base
scope :active, where(active: 1)
def self.with_stock(stock=nil)
return where(stock: 0) if stock
self
end
def self.categorized(category=nil)
return self.where(category: category) if category
self
end
def self.titled(title=nil)
return self.where("title LIKE ?", 'title') if title
self
end
def self.list(params)
title = params[:title]
category = params[:category]
page = params[:page]
self.titled(title).with_stock(stock).categorized(category)
.paginate(page).active
end
end
Controller
def index
#products = Product.list(params)
end
Do not ship Category in controller. Do it in template/partial. ONE instance variable from controller only.
I propose the specific refactoring style:
controller
class ProductsController < ApplicationController
def index
#products = Product.titled params[:title]
#products = #products.in_stock if params[:stock]
#products = #products.category params[:category] if params[:category]
#products = #products.paginate :page => params[:page]
#categories = Category.all
end
end
model
class Product < ActiveRecord::Base
belongs_to :category
...
scope :titled, proc {| title | where(active:1).where("title LIKE ?","%#{title}%")
scope :in_stock, proc { where("stock = 0") }
scope :category, proc {| category | where("category_id LIKE ?","#{category}") }
end
If your intent is just to the controller become thinner, you could move the logic to the model.
ProductController.rb
#products = Product.some_method(params)
Product.rb
def self.some_method(params)
if params[:stock]
where("stock = 0 AND active = 1 AND title LIKE ?","%#{params[:title]}%")
end
if params[:category]
where("active = 1 AND category_id LIKE ? AND title LIKE ?", "#{params[:category]}", "%#{params[:title]}%")
end
Using thin controller, fat model principle.
controller:
class ProductsController < ApplicationController
def index
#products = Product.active(params).paginate(page: params[:page])
#categories = Category.all
end
end
model:
class Product < ActiveRecord::Base
belongs_to :category
def self.active(params)
products = where(active:1).where("title LIKE ?","%#{params[:title]}%")
if params[:stock]
products = products.where("stock = 0")
end
if params[:category]
products = products.where("category_id LIKE ?","#{params[:category]}")
end
end
end

How to duplicate a group of "tasks" that belong to the same model

I'm in rails 3.0 and I'm working on a "project management" app. I'd like to duplicate an Item, which in my case is the "project", and at the same time, duplicate all tasks that belong to that item.
I stuffed my Item model with code I found here: http://www.redmine.org/projects/redmine/repository/revisions/2704/diff/trunk/app/models/project.rb, which seems to do what I want, but I can't make it work for me.
I'd like any help you can offer--general or specific! thanks!
class Task < ActiveRecord::Base
belongs_to :department
belongs_to :item
belongs_to :customer
end
class Item < ActiveRecord::Base
belongs_to :customer
has_many :tasks
def copy(item)
item = item.is_a?(Item) ? item : Item.find(item)
Item.transaction do
# Tasks
item.tasks.each do |task|
new_task = Task.new
new_task.copy_from(task)
self.tasks << new_task
end
self.save
Hook.call_hook(:model_item_copy_before_save, :source_item => item, :destination_item => self)
end
end
def self.copy_from(item)
begin
item = item.is_a?(Item) ? item : Item.find(item)
if item
# clear unique attributes
attributes = item.attributes.dup.except('id')
copy = Item.new(attributes)
copy.enabled_modules = item.enabled_modules
copy.trackers = item.trackers
copy.custom_values = item.custom_values.collect {|v| v.clone}
return copy
else
return nil
end
rescue ActiveRecord::RecordNotFound
return nil
end
end
Another thing--what is the Hook.call_hook...? I can't find any references to that on the web
Look into ActiveResource::Base#clone.
It should probably work something like:
#project = #project2.clone
#project.tasks << #project2.tasks.map(&:clone)
#project.save
EDIT:
In the context of your model you could just have:
def self.copy(item)
newitem = item.clone
newitem.tasks << item.tasks.map(&:clone)
return newitem
end
Then in your controller:
#project = Project.copy(#project_to_copy)
#project.save

Resources