3

I am new to Rails, trying to write a simple flashcard program where a user has a deck of vocabulary cards they are cycling through...

The model is a very straightforward relationship between user and card where:

 User  has_many :cards
 Card  belongs_to :user

The basic gist is that a user views a card on the index page and clicks a button, "flipping" over to the show page, where the other side is displayed.

Have created and seeded my AR database, currently rendering a functional version that accesses and "flips" card #1 in my deck, but am stuck up on accessing the second, third, fourth cards, etc.

I have tried many different variations on AR queries in my Card controller to get the next cards in the deck but none have worked... here's what I've got in my card controller now:

 def index
    @card = Card.all.next
    @cards = Card.all
  end
`

Here's my card model:

class Card < ActiveRecord::Base
  belongs_to :user

  def self.next
    n = 1 
    if self.id != Card.all.first.id
      Card.all.find_by(id: Card.all.first.id + n)
    end
    n += 1
  end

  validates :word_text, presence: true
  validates :meaning_text, presence: true
end

Here's my rake routes:

  Prefix Verb   URI Pattern                    Controller#Action
     root GET    /                              cards#index
    cards GET    /cards(.:format)               cards#index
         POST    /cards(.:format)               cards#create
 new_card GET    /cards/new(.:format)           cards#new
edit_card GET    /cards/:id/edit(.:format)      cards#edit
     card GET    /cards/:id(.:format)           cards#show
        PATCH    /cards/:id(.:format)           cards#update
          PUT    /cards/:id(.:format)           cards#update
       DELETE    /cards/:id(.:format)           cards#destroy
          GET    /cards/:id(.:format)           cards#show
`

..... So, because of the above, the code below is of course not doing what i want it to do, but here's my view page as of now:

<div id="front_page_container" class="medium-8 medium-centered text-center columns">

  <div class="row">
  </div>
</div>

<div id="box-container">

    <br> <br> <%= button_tag(type: 'button') do %>

    <h1 style="color:yellow"> <%= @card.word_text %>    

    <ul><%= link_to 'Tap to flip card', card_path(@card) %></ul>  
    <ul> <%= content_tag(:strong,'Tap to flip the card') %> </ul>

    <% end %></h1>

</div>

<br> <br> <%= button_tag(type: 'button') do %>

    <ul><%= link_to 'New Card', cards_path(@next) %></ul>  

    <ul> <%= content_tag(:strong,'New Card') %> </ul>

<% end %>

To be honest, I am very stuck on how to create a path from my index page (which is displaying card #1, or @card) BACK to a new index page where card #2, or @next, is displayed instead... any help would be much appreciated!

Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75
user3763074
  • 343
  • 5
  • 15
  • if you can please elaborate the flipping logic. currently your next method is wrong. having syntax issue. self is class in next method. self.id wont work there. – Athar Jul 19 '15 at 18:26
  • the fundamental logic of the app was that my index page would display the front of one single flashcard.... by clicking on the button ` link_to 'Tap to flip card', card_path(@card) ` the user would be taken to a show page that diplays the back side of this card. This part works ok.... but i can only see one card. the first version is up on heroku, you can see it here: https://sheltered-escarpment-2579.herokuapp.com/cards.1 thx – user3763074 Jul 19 '15 at 18:40

1 Answers1

2

Get the @next card by doing the following

@card = Card.find(params[:id])
@next = Card.where('id > ?', @card.id).first
@next = Card.first if @next.nil?

Remeber that when @card is the last card in your DB, you will want to handle that as well since @next would be nil in that case, which is the reason for the third line.

Edit: To fix your specific code, you need to modify your next method in your model like this

def next  # This is a method on an INSTANCE of Card, not the Class
  next_card = Card.where('id > ?', self.id).first
  next_card = Card.first if next_card.blank?
  next_card
end

This method is then called on @card, not Card, so something like this

<%= link_to 'New Card', card_path(@card.next) %>
Marc
  • 438
  • 1
  • 4
  • 15
  • thanks for the reply. this logic makes perfect sense, unfortunately when i run it i get an error: "Couldn't find Card with 'id'=" i tried doing playing with syntax, doing: params[:id], params[:cards_id], etc. since I am new to rails syntax, but no dice.... i'm wondering if i need to specify params[:card_id] somewhere else in my program to get it to generate a value? – user3763074 Jul 19 '15 at 19:34
  • Ah, I see a small bug in the code I had for the link_to, I used card*s*_path, when it should have been card_path(@card.next). If thats not it, then where exactly does the error occur? Controller or models 'next' method? – Marc Jul 19 '15 at 19:38
  • I wish you would have explained the way to get there instead of just giving the answer. – Jonathan Allard Jul 19 '15 at 19:45
  • good catch Marc, i updated the index to fix it. According to rails, the error is happening in the cards_controller file..... on this line: ` @card = Card.find(params[:card_id]) ` As I said, new to rails, but I'm interpreting this line as: "create an instance of Card that has the id that is identical to the user input (aka params hash).....' if that's the case, i guess i'm curious what/where this input is accounted for in the program? – user3763074 Jul 19 '15 at 19:51
  • @JonathanAllard if you are using the default 'resource' routes, cards_path will send your request to the index action. Whenever you are operating on a single resource (update, delete, show etc), the paths and urls are in the singular form. Since this is supposed to take the user to A card, it needs to be the singular form, therefore 'card_path' – Marc Jul 19 '15 at 19:59
  • The way rails routing works, a single parameter to card_path will generate a url looking like /card/ID, where the ID is taken from the object you are passing to the card_path method. By default, that will arrive in your controller as params[:id], so you should change your show method to just do @card = Card.find(params[:id]). The way you could have debugged it yourself would be to tail your development.log file and checked the parameters that are being sent to the action (first or second line of the log when the request arrives). You would see that params did not contain :card_id – Marc Jul 19 '15 at 20:04
  • ok, thanks. when i run this things are pretty much the same as before... i have card#1's front on the index page... when i click on new card, nothing happens, no error message or anything. changing my url in my browser to cards/1, cards/2, etc. will definitely give me the show pages for these words, but still unable to generate a fresh index page when i click new card. been working on this for a few hours so i will take a break and reassess later. thanks – user3763074 Jul 19 '15 at 22:01
  • If the direct links to the pages are working, it just means the code I gave you to link to the next card is wrong. What URL does the 'Next card' link point to? – Marc Jul 19 '15 at 22:06
  • 'Next card' points to '/cards', which is good... i forgot to mention, but the error above ('Couldn't find Card with 'id'=') was pointing to the index method, not the show method... so the line: @card = Card.find(params[:card_id]) in index.... was getting by this by doing: Card.find(1)... to start off on the first card... but maybe this is why it keeps repeating that card? if so, not sure how i go back to Card.find(params[:card_id]) and bypass this error – user3763074 Jul 19 '15 at 22:19
  • Just note the corrections I mentioned in the comments, I added them to my reply as well. link_to card_path(@card.next), not cards_path(@card.next). Secondly, the id will come in as params[:id], not params[:card_id]. – Marc Jul 19 '15 at 22:32
  • hmmm, i get the same error when i implement those changes.. tailed the development log and it says: Card Load (0.7ms) SELECT "cards".* FROM "cards" WHERE "cards"."id" = $1 LIMIT 1 [["id", nil]] Completed 404 Not Found in 2ms (ActiveRecord: 0.7ms) ActiveRecord::RecordNotFound (Couldn't find Card with 'id'=): – user3763074 Jul 19 '15 at 22:37
  • Ok, that means there was a bug in the next method, and I think I fixed it in my reply. Note the last line, which is just to make sure it returns the next_card object, and not whatever that if statement would have returned. To debug easily, start a rails console after the change, and try executing Card.find(1).next. It should return a card object, if it doesnt, then there is still some other bug in it. – Marc Jul 19 '15 at 22:48
  • cool, implemented that change but rails console for Card.find(1).next currently returns nil... – user3763074 Jul 19 '15 at 23:02
  • I made a quick project to test it out and the fix definitely works, did you perhaps open the console before you changed the code? If so, you should reload the app so the change takes effect by running 'reload!' in the console – Marc Jul 19 '15 at 23:19
  • this works!! thanks! i'm not sure why clicking on 'new card' brings me to the show page for card #2 and not the index page though.... sorry if this is a repetitive question – user3763074 Jul 19 '15 at 23:30
  • Why do you want the index page and not the show page? If you are sure thats what you want, then you DO need to change the 'Next' link_to to link_to cards_path(:card_id => @card.next) And in the index action of the controller, @card = Card.find(params[:card_id]). cards_path doesnt have an :id portion in normal resourceful routes, so you have to specify your parameters as URL parameters as I show above. – Marc Jul 19 '15 at 23:39