I have a Business Model and a Category Model.
Business belongs_to multiple category. What I am trying to do is building the relation without help of a third join table.
In business table there is a string column which will hold the comma separated category_id.
So I am wondering is it possible to build the relation like that. Any wise comment and idea will be appreciated.
I think it would be easier to do it with just a method:
class Business < ActiveRecord::Base
def categories
#categories ||= Category.where(id: category_ids.split(','))
end
def category_ids=(ids)
# this is needed to reset the memoization, when you change the category ids
#categories = nil
super
end
end
Related
In my rails controller I'd like to retrieve only the Projects where the current user's id is in a param array.
This is what I currently have:
class MyProjectsController < ApplicationController
before_action :authenticate_user!
def index
#user = current_user
#projects = Project.where(team_member: [#user])
end
private
def project_params
params.require(:project).permit(:name, :team_member => [])
end
end
My expectation was that this would return projects if #user was included in the array...
It actually only returns projects if #user is the only value in the array. If the array contains multiple values nothing is returned.
I'm fairly new to rails and feel like I'm missing something really obvious here.
Thanks in advance!
Update:
So I was adding Users to a Project via a column on the Projects table called :team_member which accepts an array of user IDs.
I did get this to work by doing a query like this:
#projects = Project.where(":team_member = ANY(team_member)", team_member:
[current_user.id])
This returns only projects where current_user.id exists in the :team_member array.
BUT I realize that I really need to perhaps do this with a join table on User and Projects and add users to projects that way. Thanks for the comments...they all helped me think through this.
We could help better you show us the Project model. Specifically the association between Project and team_member.
If team_member is a has_many association, you could join it and filter by their ids, like:
Project.joins(:team_members).where(team_members: { id: YOUR_ARRAY_OF_IDS })
But maybe team_member is an array, or some sort of data serialized in Project model, for that we could search array elements using ANY or ALL, using postgresql, I can't tell much about other DBMS.
Please tell more about this model and it's associations
i would suggest you to use either has_any_belongs_to_many relationship , or has_many :through for essay querying database
https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
https://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
Try this:
#projects = Project.all.where(team_member: current_user)
Tables:
User
Project has_many Results
Project has_many Data through ProjectData
Results belongs_to data, project
In the Result table I have a column :position of type int.
So I would like to get all the results with a level < 50, actually the value of count.
I am thinking in adding in the Result class
def get_top_level current_user
tsum = []
Project.where(user_id: current_user).each do |project|
tsum << project.results.where("level <= ?", 50).count
end
return sum(tsum)
end
This will work, but I feel that there should be a easy and prettier way of doing this.
And is it ok to user the class name in a view and pass different values for example:
<%=Results.get_top_level(current_user)%>
Or
<%=#results.get_top_level(current_user)%>
If none of those are a good practice, can you help me with a alternative solution for this.
Thank you.
I would create a method on the project model something like this.
def get_top_level
self.results.select{ |result| result.level <= 50 }
end
On the user model. What's the relationship here, does a user have many projects? Or just one project.
def get_top_level
self.top_level_projects.inject(:+)
end
def top_level_projects
self.projects.map(&:get_top_level)
end
Now when you call current_user.get_top_level
This will find the top_level_projects, map the associated results and add them all together.
I am trying to implement my own methods for habtm association between ActiveResource and ActiveRecord classes in my Rails app.
Here is my classes:
class Project < ActiveResource::Base
end
class Target < ActiveRecord::Base
has_and_belongs_to_many :projects
def project_ids
project_ids
end
def project_ids=(pids)
project_ids = pids
end
def projects
projects = []
pids = project_ids.split(",")
pids.each do |pid|
projects.push(Project.find(pid))
end
end
def projects=(projs)
pids = projs.collect(&:id)
project_ids = pids.join(",")
end
end
I also have join table projects_targets with two columns project_id and target_id.
This does not record the association value into the join table upon creation.
My Questions:
Is there any other approach to do this ?
Am I missing something in my association methods?
I'd really appreciate any help.
Thanks in advance for help!
My advice is to not fight the framework and use the built in methods. If you wanted to implement custom accessors, then you should switch to a has many through because it will give you a model ( of the join table ) that you can work with to set the association manually.
Start here: http://edgeguides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
You will not need the custom accessors project_ids or projects because rails will do the work magically.
You can easily do assignments like so:
some_target.projects << some_project
You don't even have to call some_target.save because the << operator is saving the association and writing the id's to the join table for you.
If you have an array of projects, or an active record relation ( like the result of a where clause) you can pass it in the same way
some_target.projects << array_of_projects
To remove the association, you can call destroy with an object like
some_target.projects.destroy a_specific_project
This won't destroy a_specific_project, but it will un-associate it.
I'm working on implementing a tagging system and I'm having problem querying for tagged objects with a scope.
For example, I would like to find all the user's items with a certain tag. With a class method I can currently find all the objects:
def self.tagged_with(name)
Tag.find_by_name(name).items
end
However, this has a problem. If I were to do something like: current_user.items.tagged_with(name) won't this existing method return ALL the items and not just items owned by the current_user? I suppose this is a simply querying issue but I can't figure out how to change a class method into something called on a collection. I have tried going the opposite way, to get a the collection through the tags, something like... tag.items.where(:user_id => current_user.id) but in this case, it's a many-to-many relationship and I haven't been able to get on thumb on this either.
What's the proper way to restrict a query like this?
Create an association on your User class that points to your Tag class.
class User < ActiveRecord::Base
has_many :tags
end
Then you can do:
current_user.tags.where(...)
If you don't already have an association in place, you'll need to create a migration to have the tags table reference your users table with a foreign key.
I think this will help you:
class Account < ActiveRecord::Base
has_many :people do
def find_or_create_by_name(name)
first_name, last_name = name.split(" ", 2)
find_or_create_by_first_name_and_last_name(first_name, last_name)
end
end
end
person = Account.first.people.find_or_create_by_name("David Heinemeier Hansson")
person.first_name # => "David"
person.last_name # => "Heinemeier Hansson"
So, basically you can define your method tagged_with directly into the association!
This example is took from the documentations ActiveRecord::Associations
I have a simple cart system that I have been working on for a little while for an application and am needing a little help in trying to figure out how to update a particular attribute in a join table (Between Order and Products).
Here is the code:
def add_product_to_cart
#product = Product.by_client(current_client).first
#order = current_order
unless #order.products.exists? :id => #product.id
#order.products << #product
end
end
I am trying to update a particular attribute when I update the #order.products...
This is what I am trying to do:
#order.products << #product --> When this happens I need to update a :price attribute..
Anyway of doing this?
class Order
has_many :products
def price
products.sum(:price)
end
end
Just off the top of my head. Here's the sum reference:
http://ar.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html#M000296
Desire to put attributes into join table may be a sign of missing model. You can promote join table into model, say OrderItem, by adding primary key to it. HABTM associations in Order and Product then become has_many through associations. The new model would be a good place for setting up callback which populates price attribute. It can also unlock additional benefits, like time-stamping items and making them act_as_list, etc.