I have a datetime column in one of my tables (team_opps) called start_date.
I am trying to write methods in my model that allow me to classify them as Monday, Tuesday, etc... opportunities.
def self.friday_team_opps
where('WEEKDAY(start_date) = ?', 4)
end
In my view I am trying to call a .each on it.
<% TeamOpp.friday_team_opps.each do |team_opp| %>
<%= render team_opp, :team_opp => :team_opp %>
<% end %>
Error is:
SQLite3::SQLException: no such function: WEEKDAY: SELECT "team_opps".* FROM "team_opps" WHERE (WEEKDAY(start_date) = 4)
Thanks
First of all, you need to define the method on the TeamOpp class by defining the method as def self.friday_team_opps.
Moreover, you can't call methods on the column since it would require ActiveRecord to load all the data in your table and then call the Ruby method on that data. What you can do is use direct SQL functions, like for example MySQL's WEEKDAY (monday = 0, tuesday = 1, etc.):
def self.friday_team_opps
where("WEEKDAY(team_opps.created_at) = ?", 4)
end
In SQLite, you can use the strftime function (sunday = 0, monday = 1, etc.):
def self.friday_team_opps
where('strftime("%w", "created_at") = "?"', 5)
end
You define it as an instance method
def friday_team_opps
And it should be defined as a class method
def self.friday_team_opps
If you want to make it a instance function then you should use it like this
def friday_team_opps
return self.start_date.strftime("%A")
end
Subsequently you will have to modify your view like this :
<% TeamOpp.select("start_date").each do |team_opp| %>
<%= team_opp.friday_team_opps() %>
<% end %>
Related
I have a scope on my user model
I want to use this scope within a block on a view to display an option
my scope looks like this
scope :can_own_project, where('superuser = ? OR projectadmin = ?', true, true)
in my view I can achieve what I am looking to do by:
#stdprojectusers.each do |projectuser| %>
<% if (projectuser.superuser == true) || (projectuser.projectadmin == true) %>OPTION<%end%>`
what I would like to do is something like
<% if projectuser.can_own_project %> OPTION <% end %>
or
<% if projectuser == User.can_own_project %> OPTION <% end %>
any advise?
thanks
I don't think you want a scope. Scope's are applied to classes. If I'm reading you right, you are working with an instance. Is there a reason you can't simply define a method on that class?
class ProjectUser << ActiveRecord::Base
def can_own_project?
superuser == true || projectadmin == true
end
end
Note, I changed your method and appended a '?'. It's a habit of mine and isn't necessary, but I like the question form myself.
Your scope should work, but performance will (over time) take a major hit. What you'd want to do is:
<% if User.can_own_project.include?(projectuser) %> OPTION <% end %>
What I think you're looking for is a helper method...
module UserHelper
def does_user_own_project?(user)
user.superuser || user.projectadmin
end
end
Your view could then look like:
#stdprojectusers.each do |projectuser| %>
<% if does_user_own_project?(projectuser) %>OPTION<%end%>
If you'll want to use this outside the scope of this view, you could also make it an instance method on User:
class User < ActiveRecord::Base
def does_user_own_project?
self.superuser || self.projectadmin
end
end
I'm trying to create a search form in my rails application. I've looked up various solutions but they make little sense to me.
I'm getting the following error when I run a search through a form in my rails app. Right now my concern (other than the error) is my instance variable #computers in my index action. I'm pretty sure it's not 'the rails way' to get a search done properly and would love some advice.
Error
undefined method `%' for #<Array:0x5780460>
Parameters after Search
http://localhost:3000/computers?utf8=%E2%9C%93&direction=&sort=&search=bob
Search Form
<%= form_tag computers_path, method: "get" do %>
<%= hidden_field_tag :direction, params[:direction] %>
<%= hidden_field_tag :sort, params[:sort] %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Go", name: nil, class: "btn btn-primary" %>
<% end %>
Call to Method
def index
#computers = Computer.where(school_id: current_user.school_id).search(params[:search]).category(params[:category]).order(sort_column + " " + sort_direction)
end
Method
def Computer.search(search)
if search
search = search.downcase
params = []
values = {}
column_names.each do |c|
params << "#{c} LIKE #{c.to_sym}"
values[c.to_sym] = search
end
params.join (' OR ')
where(params,values)
else
all
end
end
You've got the right idea, but invoking the .join method does not change the object on which it is called, it merely returns a string representation. You need to store the return in a variable, something like this: paramsStr = params.join(' OR '). Then simply pass paramsStr to the where clause.
Ultimately, that is what is causing your unidentified method % for Array .... error; this version of the where method is expecting the first parameter to be a string. Check out this documentation, the part about placeholder conditions.
Hope that helps.
I've been trying for a while to find the best way of querying for the desired result, but I always end up failing at some poing in the query.
Simplified database structure:
User:
id (integer)
first_name (string)
last_name (string)
CourseType:
title (string)
slug (string)
Course:
belongs_to :user
belongs_to :course_type
week (integer)
sold (float)
My controller is calling a scope:
#users = User.sales_results(week)
And here's the scope in my model:
scope :sales_results, lambda { |week|
joins(:courses => [:course_type])
.select("
users.id, users.first_name, users.last_name,
SUM(courses.sold) as total_sold,
COUNT(courses) as num_classes
")
.where("courses.week = ?", week)
.group('users.id')
}
This works fine, and I can use it in my template to show the total amount sold. Although I also want to show a second column where the value sold for some specific types of courses are summed up in. Something like this:
<% #users.each do |user| %>
<%= user.total_sold %>
<%= user.total_sold.where("course_types.slug IN ('H', 'S')") # not possible, but similar to what I desire %>
<% end %>
Update
I ended up adding another scope
scope :sales_results_for_types, lambda { |week, types|
sales_results(week).except(:group).where("course_types.slug IN (?)", types)
.group('users.id')
}
Then calling both scopes in my controller
#users = User.sales_results(...)
#users_filtered = User.sales_results_for_types(...)
Lastly iterating both results at the same time
<% #users.zip(#users_filtered).each do |user, filtered| %>
<%= filtered.total_sold %>
<%= user.total_sold %>
Until I figure out something better. Thanks guys for leading me on the right track.
If you are ok with having another query, you can use this
user.joins(courses: :course_type).sum(:sold, group: 'course_types.slug')
which will give you a hash where the keys are the slugs, and the values are the sums.
This seems like it should be a common problem but I'm having trouble finding an answer. Basically I want to have a form with 10 or so checkboxes which I'm creating with check_box_tag. When the form is submitted I want to generate a query that return all records that match ANY of the checked selections. So, the number of checked selections will vary.
So, for example, if I have
class Book < ActiveRecord::Base
belongs_to :author
end
I want to generate something like
Book.where("author_id = ? or author_id = ?", params[authors[0]], params[authors[1]]) if there are two boxes checked, etc.
Thanks for any insight.
Will this work for you?
Book.where(author_id: [array_of_author_ids])
You need to collect author_ids from params first
I recently had to do something similar, this is how I achieved this. It's pretty clever (at least I think so. :))
I created a query model that serializes the query column (text field) in JSON. I use a form to get the query data from the user with selection fields.
class BookQuery < ActiveRecord::Base
has_many :books
# loop through each foreign key of the Book table and create a hash with empty selection
def self.empty_query
q = {}
Book.column_names.each do |column_name|
next unless column_name.ends_with?("_id")
q.merge column_name => []
end
end
end
I'm using Author as an example below:
<%= form_for #book_query do |f| %>
<% for author in Author.all %>
<%= check_box_tag "book_query[query][author_ids][]", author.id, false%>
<%= author.name %>
<% end %>
<%= f.submit "Save Query" %>
<% end %>
When this form is submitted you ended up with parameters like this:
When the form is submitted it generates this parameter:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XXXXXXXXXXX", "book_query"=>{"query"=>{"author_ids"=>["2", "3"]}}, "commit"=>"Save Query"}
Now in the BookQuery controller's create action you can just do what create function always does:
def create
#book_query = BookQuery.build(params[:book_query])
if #book_query.save
flash[:success] = "Book query successfully saved."
redirect_to ...
else
flash[:error] = "Failed to save book query."
render :new
end
end
But by default rails serializes the data in hash type:
1.9.3p194 :015 > pp BookQuery.find(9).query
BookQuery Load (0.7ms) SELECT "book_queries".* FROM "book_queries" WHERE "book_queries"."id" = $1 LIMIT 1 [["id", 9]]
"--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nauthor_ids:\n- '2'\n- '3'\n"
=> "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nauthor_ids:\n- '2'\n- '3'\n"
In BookQuery model, add the following:
serialize :query, JSON
But rail would change the IDs to string:
1.9.3p194 :018 > query = JSON.parse(BookQuery.find(10).query)
BookQuery Load (0.5ms) SELECT "book_queries".* FROM "book_queries" WHERE "book_queries"."id" = $1 LIMIT 1 [["id", 10]]
=> {"author_ids"=>["2", "3"]}
1.9.3p194 :019 > query["author_ids"]
=> ["2", "3"]
What I did then is override the attribute accessors in BookQuery model:
The below has to be done because the hash returns strings, not ids in integer.
def query=(query)
query.each_pair do |k, v|
if query[k].first.present?
query[k].map!(&:to_i)
else
query.except!(k)
end
end
write_attribute(:query, query)
end
# just want to avoid getting nil query's
def query
read_attribute(:query) || {}
end
To find book with this query, you can simply add this function to your Book model:
def self.find_by_book_query(book_query, options = {})
options[:conditions] = book_query.query
find(:all, options)
end
Now you get a customizable query string based on the model definition Book and everything works like the Rails way. :)
I have in my controller this:
#itemsok = Search.where("first_item_id = ?", params["3"])
This is sopposed to be a query in the search table of the database asking for all the searches that have a first_item_id = 3 ...
Question 1 .- The syntax is I found it in http://guides.rubyonrails.org/active_record_querying.html but im not sure if im using it right?
Ok the question 2 is, I have this on the controller, is it ok to have querys in the controller?
In the view im printing the variable <%= #itemsok %> and all I get is a
ActiveRecord::Relation:0x007fd3d3e894d8
Any suggestions?
Thanks in advance.
ActiveRecord 3 lets you chain relations together so you can do something like this:
#itemsok = Search.where("first_item_id = ?", params["3"]).where("foo = ?", "bar")
The where() function returns an ActiveRecord::Relation. Generally this isn't a problem, since if you use the object it'll automatically run the query and return the results on the object so you'll get the database objects. AR doesn't run the query until it's actually needed.
Where will return a list of items (Array), so if you're just debugging, change your view to this:
<%= debug #itemsok.to_a %>
You seem to be constructing the query wrong way.
If you want to search for records with first_item_id = 3, you should do:
Search.where("first_item_id = ?", 3)
This will return an array of matching records, something you can't easily print with <%= #itemsok %>. You should iterate over the elements and print each one:
<% #itemsok.each do |item| %>
<%= item.name %>
<% end %>
I'd also suggest defining to_s method for the objects you want to print.
class Search
def to_s
name
end
end
Then you can simply print the object and to_s method will be automatically called for you:
<% #itemsok.each do |item| %>
<%= item %>
<% end %>
The right way to do is to define a namedscope in the model and then use it in the controller.
Something similar to this :
class Search < ActiveRecord::Base
named_scope:item_ok,lambda {|*args|{:conditions=>["item_id >= ?", args.first]}}
end
and then call the namedscope from the controller like this :
#itemsok = Search.item_ok(params[:value])