简体   繁体   中英

How to loop through all available arrays in Ruby code

I am trying to create a dashboard where users (User model) who has clicked "attending" (which is a flaggable) to an event (Event model) which is connected to a Collection (Collection model) will be able to see what are the Events they are going for.

My question however, is simply how to loop through all possible arrays in order for me to get all the associated IDs for the Events that the User has clicked "attending".

So for example, in my home page I want to display all possible events that the user is attending:

user_statistics.html.erb

<div class="span3 events">
    <h3>Events</h3>
    <% if @events.empty? %>
        <p>You are currently not attending any events.</p>
    <% else %>
        <p>You are attending: <b><%= pluralize(@events.count, "event") %></b></p>
        <p>Event 1: <%= @event1_name %> on Date: <%= @event1.date %> at Time:<%= @event1.time %></p>
    <% end %>
</div>

pages_controller.rb

    def home
    @title = "Title"
    @user = current_user
    if current_user
        @post = Post.new
        @feed_items = current_user.feed
        @user_following = @user.following
        @user_followers = @user.followers
        @events = @user.flaggings.with_flag(:attending)
        @event1 = Event.find(@events[0].flaggable_id)
        @event1_name = Collection.find(@event1.collection_id).name
    end
end

I have set the @event1 array to 0 to access the first flag for 'attending', and then get the flaggable_id so I have the id to call up the Collection.

My issue is that if I have several events, how do I go about looping through to all the arrays to ensure I can pull out all the Collections?

For the first User who has clicked "attending" for 2 events, this is the data:

in IRB, for User.first who is attending 2 events

  User Load (0.3ms)  SELECT "users".* FROM "users" LIMIT 1
  MakeFlaggable::Flagging Load (0.4ms)  SELECT "flaggings".* FROM "flaggings" WHERE 
"flaggings"."flagger_id" = 1 AND "flaggings"."flagger_type" = 'User' AND 
"flaggings"."flag" = 'attending'
 [#<MakeFlaggable::Flagging id: 16, flaggable_type: "Event", flaggable_id: 3, 
flagger_type: "User", flagger_id: 1, flag: "attending", created_at: "2012-02-20 09:26:36", 
updated_at: "2012-02-20 09:26:36">, #<MakeFlaggable::Flagging id: 18, flaggable_type: 
"Event", flaggable_id: 4, flagger_type: "User", flagger_id: 1, flag: "attending", 
created_at: "2012-02-20 10:38:00", updated_at: "2012-02-20 10:38:00">] 

You can see that the user has flagged 'attending' for 2 events, which are stored in arrays. Hence if I have 2 events, I would ideally want to loop through such that I have 2 arrays.

I find it quite confusing to implement this... any help would be much appreciated!

user.rb partial code

Class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :user_bio, 
                :shop, :cover_photo, :avatar, :remote_image_url
has_secure_password
mount_uploader :cover_photo, ImageUploader
mount_uploader :avatar, ImageUploader

make_flagger

scope :shop, where(shop: true)

has_many :posts,                    dependent: :destroy
has_many :relationships,            dependent: :destroy,
                                    foreign_key: "follower_id"
has_many :reverse_relationships,    dependent: :destroy,
                                    foreign_key: "followed_id",
                                    class_name: "Relationship"

has_many :following, through: :relationships, source: :followed 
has_many :followers, through: :reverse_relationships, source: :follower 

has_many :collections,              dependent: :destroy 
...
end

collections.rb partial code

class Collection < ActiveRecord::Base
attr_accessible :name, :description, :image, :remote_image_url
belongs_to :user
has_many :products,     dependent: :destroy
has_many :events,       dependent: :destroy
mount_uploader :image, ImageUploader
make_flaggable :like
...
end

events.rb partial code

class Event < ActiveRecord::Base
attr_accessible :date, :time, :description
belongs_to :collections
make_flaggable :attending
...
end

It's not 100% clear from your post, but it sounds like you need a named scope for Events where the attending flag is set and a has_many :through association to let the User have Events. With those two bits together, you could do something like:

User.first.events.attending

and AREL will take care of wiring that all up into a nice fast query for you.

Is flaggable a gem or have you written it as a polymorphic class?

This line is kind of nasty (sorry):

@events = @user.flaggings.with_flag(:attending)

The @events variable isn't holding events - it's holding a collection of flaggings. As a naming convention, this is obviously bad.

Also, this line is probably redundant if you've set up (or used a gem) for the flaggable polymorphic relationship:

@event1 = Event.find(@events[0].flaggable_id)
#This could be rewritten as:
@event1 = @events.first.flaggable

Or even nicer, combine the two previous lines into:

#@events = @user.flaggings.with_flag(:attending)
#@event1 = Event.find(@events[0].flaggable_id)
#becomes:

flaggings = @user.flaggings.with_flag(:attending)
@events = flaggings.map(&:flaggable)

@jxpx777 makes a very good point about named scope and hmt associations. This is probably the way forward. You could do something like this:

Class User < AR...

has_many :attendances, :class => 'Flagging', :conditions => {:flag => 'attending'} #You might need to add :type => "Event" if you use flaggings elsewhere...

has_many :events_attending, :class => 'Event', :through => :attendances, :source => :flaggable_id #You'll probably have to change a lot of these variable names - I can't see the rest of your source code...

That will then give you ability to just do:

@events = @user.events_attending.include(:collection)

Caveat - none of this code is tested - it's all off the top of my head, but it should point you in the right direction at least

Okay, I managed to solve my own problem albeit in a very dirty manner...

pages_controller.rb

    def home
    @title = "Simplifying and socializing online shopping - Ruuva"
    @user = current_user
    if current_user
        @post = Post.new
        @feed_items = current_user.feed

        @user_following = @user.following
        @user_followers = @user.followers

        @events_attending = @user.flaggings.with_flag(:attending)
    end
end

_user_statistics.html.erb partial

        <h3>Events</h3>
    <% if @events_attending.empty? %>
        <p>You are currently not attending any events.</p>
    <% else %>
        <p>You are attending these events:</p>
        <ol>
            <% @events_attending.each do |e| %>
                    <% unless Event.find_by_id(e.flaggable_id).nil? %>                      
                    <li>
                        Collection: <%= link_to Collection.find(Event.find(e.flaggable_id).collection_id).name, event_path(e.flaggable_id) %>
                        <br>happening on: <%= Event.find(e.flaggable_id).date %> at <%= Event.find(e.flaggable_id).time %>
                    </li>
                    <% end %>
            <% end %>
        </ol>
    <% end %>

I'm pretty sure the code is very bad, and I DO used several 'shortcuts' issues that will bite me back in the future... but an mvp is an mvp. Thanks guys for the help, though! :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM