0

I've got a timeline that is being built from dynamically generated JSON. What should be happening is that it loops through a given user's events and the timeline is populated with these.

It was working fine when I was accessing it as the current_user. I have modified the code to use @access_user instead of current_user, so that I can access it whilst logged in as that user's moderator.

In this case, the app is trying to populate the timeline with an event with the ID of 21 (which doesn't exist - 21 is the ID of the event's user).

This now doesn't work whether I am logged in as a user or moderator etc - so it's an issue that @access_user is creating I'm guessing.

Can anyone tell me why this is happening, and how I can fix it? Thanks!

JS that calls initializes the timeline:

$(document).ready(function() {
                createStoryJS({
                    type:       'timeline',
                    width:      '820',
                    height:     '600',
                    source:     '/users/<%= @access_user.id %>/events.json?callback',
                    embed_id:   'my-timeline',
                    font:       'Euphoria-Droid',
                    debug:      true,
                    gmap_key:   '#',
                    maptype:    'HYBRID'
                });
            });

This processes correctly to /users/21/events.json?callback

This is how @access_user is being set:

  def access_user
    if user_signed_in?
      @access_user = current_user
    elsif keyholder_signed_in?
      @access_user = current_keyholder.user
    elsif guest_signed_in?
      @access_user = current_guest.user
    end
  end

@access_user seems to work fine if I call <%= @access_user.id %> in a view.

This is the json.json_builder file that should be populating the timeline:

timeline do
  headline @access_user.first_name
  type "default"
  text "A Timeline"
  startDate ""
  date @events do |event|
    startDate event.start_date.strftime('%Y,%m,%d')
    endDate ""
    headline event.headline
    text event.text
    asset do
        media event.media
        caption event.caption
    end
  end
end

And this is the myevents action in the events controller:

  def myevents
    @events = @access_user.events
    respond_with @users
  end

And the trace:

Started GET "/users/21/events.json?callback?callback=onJSONP_Data" for 127.0.0.1
 at 2013-08-20 13:09:28 +0100
Processing by EventsController#myevents as JSON
  Parameters: {"callback?callback"=>"onJSONP_Data", "id"=>"21"}
  ←[1m←[35mKeyholder Load (2.0ms)←[0m  SELECT "keyholders".* FROM "keyholders" W
HERE "keyholders"."id" = 5 LIMIT 1
  ←[1m←[36mUser Load (3.0ms)←[0m  ←[1mSELECT "users".* FROM "users" WHERE "users
"."id" = 21 LIMIT 1←[0m
  ←[1m←[35mEvent Load (5.0ms)←[0m  SELECT "events".* FROM "events" WHERE "events
"."id" = ? LIMIT 1  [["id", "21"]]
Completed 404 Not Found in 51ms

ActiveRecord::RecordNotFound (Couldn't find Event with id=21):
  activerecord (3.2.14) lib/active_record/relation/finder_methods.rb:344:in `fin
d_one'
.
.
.

Update: Relevant parts of routes.rb:

resources :events do
    member do
      get 'myevents'
    end
  end

match 'users/:id/events' => 'events#myevents'

Update: new trace when logged in as a guest (after changing member to collection on routes) User ID=2, guest ID=2:

Started GET "/timelines/4" for 127.0.0.1 at 2013-08-20 16:33:41 +0100
Processing by TimelinesController#show as HTML
  Parameters: {"id"=>"4"}
  ←[1m←[36mGuest Load (2.0ms)←[0m  ←[1mSELECT "guests".* FROM "guests" WHERE "gu
ests"."id" = 2 LIMIT 1←[0m
  ←[1m←[35mUser Load (10.0ms)←[0m  SELECT "users".* FROM "users" WHERE "users"."
id" = 2 LIMIT 1
  ←[1m←[36mTimeline Load (1.0ms)←[0m  ←[1mSELECT "timelines".* FROM "timelines"
WHERE "timelines"."id" = ? LIMIT 1←[0m  [["id", "4"]]
  Rendered timelines/_show_timeline.html.erb (1.0ms)
  Rendered timelines/_my_timeline.html.erb (1.0ms)
  Rendered timelines/_new_event.html.erb (339.0ms)
  ←[1m←[35mEvent Load (2.0ms)←[0m  SELECT "events".* FROM "events" INNER JOIN "t
imelines" ON "events"."timeline_id" = "timelines"."id" WHERE "timelines"."user_i
d" = 2
  ←[1m←[36mEXPLAIN (0.0ms)←[0m  ←[1mEXPLAIN QUERY PLAN SELECT "events".* FROM "e
vents" INNER JOIN "timelines" ON "events"."timeline_id" = "timelines"."id" WHERE
 "timelines"."user_id" = 2←[0m
EXPLAIN for: SELECT "events".* FROM "events" INNER JOIN "timelines" ON "events".
"timeline_id" = "timelines"."id" WHERE "timelines"."user_id" = 2
0|0|0|SCAN TABLE events (~1000000 rows)
0|1|1|SEARCH TABLE timelines USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)

  Rendered timelines/_edit_events.html.erb (1034.1ms)
  Rendered timelines/_delete_events.html.erb (5.0ms)
  Rendered timelines/show.html.erb within layouts/application (3915.2ms)
  ←[1m←[35mFuneral Load (4.0ms)←[0m  SELECT "funerals".* FROM "funerals" WHERE "
funerals"."user_id" = 2 LIMIT 1
  ←[1m←[36mTimeline Load (1.0ms)←[0m  ←[1mSELECT "timelines".* FROM "timelines"
WHERE "timelines"."user_id" = 2 LIMIT 1←[0m
  ←[1m←[35mKeyholder Load (2.0ms)←[0m  SELECT "keyholders".* FROM "keyholders" W
HERE "keyholders"."user_id" = 2 LIMIT 1
  Rendered partials/_guest_options.html.erb (395.0ms)
Completed 200 OK in 12947ms (Views: 9729.6ms | ActiveRecord: 133.0ms)


Started GET "/users/2/events.json?callback?callback=onJSONP_Data" for 127.0.0.1
at 2013-08-20 16:33:58 +0100
Processing by EventsController#myevents as JSON
  Parameters: {"callback?callback"=>"onJSONP_Data", "id"=>"2"}
  ←[1m←[36mGuest Load (17.0ms)←[0m  ←[1mSELECT "guests".* FROM "guests" WHERE "g
uests"."id" = 2 LIMIT 1←[0m
  ←[1m←[35mUser Load (3.0ms)←[0m  SELECT "users".* FROM "users" WHERE "users"."i
d" = 2 LIMIT 1
  ←[1m←[36mEvent Load (3.0ms)←[0m  ←[1mSELECT "events".* FROM "events" WHERE "ev
ents"."id" = ? LIMIT 1←[0m  [["id", "2"]]
Completed 404 Not Found in 149ms

ActiveRecord::RecordNotFound (Couldn't find Event with id=2):
ecs
  • 708
  • 1
  • 14
  • 33
  • Your ID is coming from your users resource (i.e. `/users/21/events.json` is going to set id=21 in your params hash). You need to define the event id as a separate parameter, perhaps? What do UsersController#events and EventsController#myevents methods look like? – GSP Aug 20 '13 at 14:29
  • The myevents method is above, and I don't have an events method in the users controller. This was working fine up until I started using @access_user instead of current_user - it doesn't work now even when I am logged in as a user. I don't understand this as when logged in as a user, access_user should equal the current_user object - or could it be that it's only passing the id and not the associated parameters? – ecs Aug 20 '13 at 14:33
  • Do you set up a custom route in your `users` resource to forward to the Events controller? The id is coming from the route which you say is correct. Where is the call to `find_one` that you see in the log trace? Is that in the user model for `events`? – GSP Aug 20 '13 at 14:39
  • If I was to go out on a limb, since there's almost no code in the `myevents` method. I would guess that there's a `before_action` (or something similar) on the `Events` controller that attempts to query an Event from the `:id` in the params hash. Since :id is begin set from the router as the User's id instead of an Event's id then you get the error? – GSP Aug 20 '13 at 14:42
  • The @access_user is being set in a method in the applications controller, which is called in a before_filter. It needs to be in a before_filter as otherwise it doesn't seem to work - it doesn't recognise e.g. current_user otherwise. Is that what's probably breaking this then? – ecs Aug 20 '13 at 14:45
  • I've added the routes to the question. How can I ensure that it is the events associated with the user that are being passed to the timeline, and not the id of the user? – ecs Aug 20 '13 at 14:46
  • Perhaps.... For whatever reason, it appears the the `id` value is being used in two queries: 1. to select your `@access_user` and 2. an accidental second time where it attempts to use the `id` to query an `Event`. Same parameter being used twice and the second time is where the specific error appears to be thrown. Perhaps you can search through your code base for queries that look like `Event.find_one(params[:id])`? – GSP Aug 20 '13 at 14:49

1 Answers1

0

After seeing the routes, I think I know what's going on. You set the routes "member" instead of routes "collection". As a "member" it will always attempt to search for the Event defined in the id (an id that, in this case because of the match clause in your routes, is actually coming from the User). Change your routes to:

resources :events do
  collection do
    get 'myevents'
  end
end

There's a nice answer here: difference between collection route and member route in ruby on rails?

Community
  • 1
  • 1
GSP
  • 3,763
  • 3
  • 32
  • 54
  • Unfortunately that hasn't worked, I'm still getting the same problem. How can I explicitly define what parameters I want passing as that seems to be the issue here? Thanks for your help. – ecs Aug 20 '13 at 15:36
  • Are you getting exactly the same stack trace? It still ends with `SELECT "events".* FROM "events" WHERE "events "."id" = ? LIMIT 1 [["id", "21"]] Completed 404 Not Found in 51ms` and `ActiveRecord::RecordNotFound (Couldn't find Event with id=21):` – GSP Aug 20 '13 at 15:54
  • As far as adding different params, I think you can simply add them to your source (e.g. `/users/<%= @access_user.id %>/events.json?event_id=<%= some_id %>&callback'`) but this won't help since your error (unless it has changed) is because the "id" param is being used. – GSP Aug 20 '13 at 15:56
  • I've added the new trace to the question. This time I was logged in as the guest linked to the user account. I do want the id being passed in the json callback as it is supposed to be looking for all the events associated with that user. I think that possibly it is getting an error as the json is looping through `@events`, but perhaps I have defined the wrong thing as `@events` in the myevents action? – ecs Aug 21 '13 at 09:06
  • It looks like the same issue. Somewhere either explicitly (e.g. in a before_filter or within a helper or model) or implicitly (e.g. because a route is set up to use `member` instead of `collection`) the value of `params[:id]` is being passed to a query for `Event`. – GSP Aug 21 '13 at 12:29
  • 1
    I've accepted the answer as it pointed me in the right direction - thanks for your help. It was actually an issue with the abilities set in CanCan - I was trying to use a custom action (myevents) in ability.rb - as soon as I moved the authorization for that action to a custom authorization method, it worked. So it was the cancan before filters that were mucking this up. Thanks again. – ecs Aug 21 '13 at 15:46
  • Congratulations on tracking this down! – GSP Aug 21 '13 at 17:45