Querying with comparison of multiple relationships in rails - ruby-on-rails

I have a structure like this:
A Position has_many Requests
A Request belongs_to a User
A Group has_many :members, through: :memberships, source: :user
I would like to get all groups where not all members has a particular request.
UPDATE: I have a form were I can search for individual users and groups.
I can click a user and send him/her a request (and by that, create a request).
I can also click a group and send every user in that group a request in the same manner.
The position has multiple requests, and one request has one user.
As you can see, I can make sure that no user, having a request to a given position is shown in the search result.
Bottom line: If every member in a group has a request to a given position, the group should not appear in the search result. If not all members of that group has a request, the group should be shown.
Right now I manage to get individual users that doesn't belong to the request:
#users = User.search(query_str).where.not(id: #position.requests)
I'm trying to do something like
#groups = Group.search(query_str).where.not(
#position.request.include?(all users of a Group))
I made a method in Position < ActiveRecord::Base:
def user_exists?(user)
# Check if user exists in position
self.requests.map(&:user_id).include?(user.id)
end
def all_users_exists?(users)
users.each do |user|
unless self.user_exists? user
return false
end
end
true
end
The way I can come up with to filter out groups using this method is in the views when iterating over all groups, which feels like a terrible solution.
<% #groups.each do |group| %>
<% unless #position.all_users_exists? group.members %>
# Print list-item...
Could anyone please help me filtering out the groups with all members in a request when querying instead?
Oh, and I'm using rails 4.2.5
Thanks!

Related

Specify table for rails .where

Can't find same question. How can I specify select.where for model?
I need to select from different tables by one model and want to get something like this in controller:
params[:id] = 1248 // here is example of request params
id=params[:id] // this id goes to message SQL like table name with prefix:
Message(id).all => select * from messages_1248
How can I get something like this?
Thanks for answers!
UPD:
I have one table with users and many tables with messages (each table is for one pair of users). In users table there is 'messages' column with messages tables id's. And inside user_controller I need to run a query like in my question. Maybe anybody can share an example?
how about little bit change the design, with just 2 tables (user and message) just idea with details below
user table (id,name)
messages table(user_id,message_text)
you setup the relation user has_many messages (please see this link for more guide http://guides.rubyonrails.org/association_basics.html#the-has-many-association
user.rb
has_many :memberships
message.rb
belongs_to :user
for example you need to access user with specific id and the messages for this user
inside users_controller.rb
def show
#user = User.find(params[:id])
# this find user
#messages = #user.messages
# get all the messages for specific users
end

List all Items from User by its foreign key

I am using ActiveAdmin and i want to list items which belong to a specific user. The two resources have the has_many and belongs_to relationship.
An index pages is listing all the users. Now i would like to render a show block for each user his items.
My show looks now something like this:
ActiveAdmin.register User do
show do
panel "Specific Item List" do
table_for Item.where("user_id=1").fnidi_each do |i|
column("ID"){|item|item.id}
column("Name"){|item|item.name}
end
end
end
end
How do i inherit the user_id from the page to the show panel ? So that each time show is called i can use the users id for the query.
I know these a basic question but my knowledge of Rails/AA is so far quite basic as well ;) Happy for any advice.
Looking at this code from the ActiveAdmin documentation, where "post" seems to be dynamically generated within the register block suggests that in your case you may be able to just do "user.id", etc.
ActiveAdmin.register Post do
show do
h3 post.title
div do
simple_format post.body
end
end
end
So you might try user.items or Item.where(user_id: user.id) instead of your Item.where("user_id=1").

Rails ActiveAdmin and has_many association

I am fairly new to active_admin, I was wondering if there is a way to achieve the following
I have two models
User
belongs_to :group
Group
has_many :users
I have successfully created pages in activeadmin for groups and users, now what I want is show users that belong to a certain group. I have button manage_members on groups index page which should show members of only that group. Where I can remove members from the group or add more members.
This is what I have been able to do so far
member_action :manage_members do
#group = Group.find(params[:id])
#page_title = "Manage Groups > ##{#group.name}, Edit Members"
end
and a the view app/vies/admin/groups/manage_users.html.arb
table_for assigns[:group].users do
column "Name" do |u|
u.user_id
end
column "email" do |u|
u.user.email
end
column "Created Date" do |u|
u.user.created_at
end
column "OfficePhone" do |u|
u.user.office_no
end
end
This shows the member of the groups, but I have to do all the work on this page to add edit delete a member, I cannot have active_admin filters and other cool stuff here, this is like a custom page,
Is there a way to have an index page (with all goodness of filters batch actions etc) ( like that of users ) but only showing users of a group. Something like a scoped index page which shows on users from a group and I have the same control over that page as any active admin index page ? More like the image below
rather than having to do all that work my self which currently looks like
Very new to active_admin so apologies if there something really straight forward that I am missing.
Thanks
Maybe a filter will do. That would look like (put it in the same file where you put the member_action)
filter :group, :as => :select, :collection => proc { Group.for_select }
The proc is there to make sure changes to groups (adding/removing/..) are immediately reflected to the select-list in the filter. That has to do with class caching in production.
Dont forget to put this scope in your Group model.
scope :for_select, :select => [:id, :name], :order => ['name asc']
Another way is to use scopes. If you have a field in your Group model, like a slug/label that could serve as a method header then you could do something like this in your activeadmin user register block:
Group.all.each do |group|
# note the sanitization of the Group name in the gsub
scope "#{group.name.gsub(/-/,'_')}".to_sym
end
And this in your User model:
Group.all.each do |group|
# note the sanitization of the Group name in the gsub
scope "#{group.name.gsub(/-/,'_')}".to_sym, joins(:group).where("group.name = ?",role.name)
# using joins(:group) or joins(:groups) makes a difference,
# so not sure as I have not tested, but maybe the where should be
# ....where("groups.name = ....
end
It should give you nice buttons above your index views like here: http://demo.activeadmin.info/admin/orders
If you want this for a has_and_belongs_to_many relation, I suggest you take a look at this Rails3 Active Admin - How to filter only records that meet all checked items in collection
Good luck!

Add customer_id to order when placed, retrieve it in customer index

I'm trying to create an ordering system so that when an order is placed, the customer logs in/registers and the order is added to their index. I have two controllers and all their respective models/views etc - called orders and customers. I'm assuming I'd need to add a method so that the customer_id is added to the order when it is placed, and then I could display all orders with that id in that particular customer's index - i.e. they can only see their own orders.
It's probably quite a simple question, apologies! But I'm new to rails and can't figure out how to get started on this one. Please can someone suggest how I would go about doing this?
Edit:
Thanks for everyone's help! How would I get the customer index to display only orders for that customer? Would I store the customer_id in a session when they log in, then place that in the order, then find all orders with that id in the index page? I think I know how to get their id into a session at login, but am unsure how to extract this into the customer index view. Any help would be much appreciated!
IF you create your orders table to have a customer_id, and fill that id when the customer places an order, then the customer view of orders should always be scoped to their orders. You will need to differentiate between a customer user and your admin user (perhaps you?), as in (something like):
class customer
has_many :orders
end
class order
belongs_to :customer
end
class OrdersController
def index
# determine the current customer (or admin), then
if current_user.isAdmin?
#orders = Order.all
else
#orders = current_user.orders
end
end
end
#railsdog is correct, however, here is the other part of the puzzle (how to get your customer's ID in the order in the first place):
class OrdersController
def create
#order = Order.new(params[:order])
#order.customer_id = current_user.id
# ...
end
#...
end
Note here the approach of setting the customer_id in the controller, not from the form. The reason for this is that even a hidden form field can be changed by the client, so if you did that without checking on the server side, an attacker could place orders for other customers.

Displaying Posts by number of "vote" records in separate table

I am new to Rails so go easy. I have created a blog and also created the ability for users to indicate they "like" a particular post. The way I am implementing this is by using the post table and a separate table 'vote'. When the user clicks the "like" button it sends the record to the 'vote' table with a value of '1' and the particular post id.
I would like to display the "most liked" posts in the sidebar. How do I go about calling such a thing. I would like to display the post_title and the number of 'votes', that is, I would like to somehow query the 'vote' table for the post_id's that have the most records and display them in descending order.
I hope this is an easy question.
There are several ways to accomplish this, but probably the most versatile and Rails-ish would be to create a module with a method to do the ranking, and then have any classes or associations that can be "liked" extend that module.
# lib/likable.rb
#
module Likable
def most_liked (limit = 10)
# This may be possible without a find_by_sql... see the API docs.
find_by_sql("SELECT Posts.*, SUM(votes.count) AS num_votes FROM Posts, Votes WHERE Posts.id = post_id GROUP BY post_id ORDER BY num_votes DESC LIMIT #{limit}")
end
end
# app/models/post.rb
#
require 'likable'
class Post < ActiveRecord::Base
extend Likable
# ...whatever else you've got in here
end
# app/models/user.rb (or any other model with things that can be "liked")
#
require 'likable'
class User < ActiveRecord::Base
has_many :posts, :extend => Likable
# ...the rest of the User class
end
This lets you do things like...
Post.most_liked # => an array of the 10 most liked posts
#some_user.posts.most_liked(5) # => that user's 5 most liked posts
If you needed to later, you could add methods to the module to see, eg, how many votes a particular Post has. You could also change the post_id to a target_id in Vote and make it a polymorphic association, and then you could use your Likable module to vote for anything, not just posts (you would need to generalize the call to find in most_liked if you did that).
This is actually best done by adding a counter cache to the post model, avoiding the database count on every load.
This railscast episode explains how to setup the counter cache.
Assuming you named your counter cache votes_count, you can do this to get the 10 most popular posts from your controller.
#popular_posts = Post.find(:all, :limit => 10, :order => "votes_count DESC")

Resources