Mongoid/Rails 4 Documents not found error - ruby-on-rails

Im trying to use the alternative of "foreign keys", embedded_in and embeds_many in rails 4. I'm sure there is a way round this and its making sense to me so far
My Models:
class Line
include Mongoid::Document
include Mongoid::Timestamps
embeds_many :stations
field :line, type: String
index({ starred: 1 })
end
class Station
include Mongoid::Document
include Mongoid::Timestamps
has_many :routes
embedded_in :line, inverse_of: :stations
field :name, type: String
end
Now I'm able to create a nested route such as:
http://localhost:3000/lines/:line_id/stations
with:
Rails.application.routes.draw do
resources :lines do
resources :stations
end
resources :routes
root 'lines#index'
end
My Stations Controller:
class StationsController < ApplicationController
before_action :load_line
before_action :set_station, only: [:show, :edit, :update, :destroy]
# GET /stations
# GET /stations.json
def index
#stations = #line.stations
end
# GET /stations/1
# GET /stations/1.json
def show
end
# GET /stations/new
def new
#station = #line.stations.build
end
# GET /stations/1/edit
def edit
end
# POST /stations
# POST /stations.json
def create
#station = #line.stations.build(station_params)
respond_to do |format|
if #station.save
format.html { redirect_to #station, notice: 'Station was successfully created.' }
format.json { render :show, status: :created, location: #station }
else
format.html { render :new }
format.json { render json: #station.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /stations/1
# PATCH/PUT /stations/1.json
def update
respond_to do |format|
if #station.update_attributes(station_params)
format.html { redirect_to #station, notice: 'Station was successfully updated.' }
format.json { render :show, status: :ok, location: #station }
else
format.html { render :edit }
format.json { render json: #station.errors, status: :unprocessable_entity }
end
end
end
# DELETE /stations/1
# DELETE /stations/1.json
def destroy
#station.destroy
respond_to do |format|
format.html { redirect_to stations_url, notice: 'Station was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_station
#station = #line.stations.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def station_params
params.require(:station).permit(:name)
end
def load_line
#line = Line.find(params[:line_id])
end
end
but when I visit the route I get:
message: Document(s) not found for class Line with id(s) :line_id. summary: When calling Line.find with an id or array of ids, each parameter must match a document in the database or this error will be raised. The search was for the id(s): :line_id ... (1 total) and the following ids were not found: :line_id. resolution: Search for an id that is in the database or set the Mongoid.raise_not_found_error configuration option to false, which will cause a nil to be returned instead of raising this error when searching for a single id, or only the matched documents when searching for multiples.

In your browser don't type http://localhost:3000/lines/:line_id/stations but http://localhost:3000/lines/1/stations !
If your routes.rb doesn't have the following you shoudl add it.
resources :lines do
resources :stations
end
PS: Please indent with two specs, they are common practice amongst ruby programmers.

Related

Invalid single-table inheritance type: dog is not a subclass of Pet

I have not idea what is going wrong here. I generated the new app to check something out.
I generated everything using rails g scaffold Pet name:string type:string
When I try creating a new pet I get the error:
Invalid single-table inheritance type: dog is not a subclass of Pet
What could be the issue?
Migration
class CreatePets < ActiveRecord::Migration
def change
create_table :pets do |t|
t.string :name
t.string :type
t.timestamps null: false
end
end
end
Controller
class PetsController < ApplicationController
before_action :set_pet, only: [:show, :edit, :update, :destroy]
# GET /pets
# GET /pets.json
def index
#pets = Pet.all
end
# GET /pets/1
# GET /pets/1.json
def show
end
# GET /pets/new
def new
#pet = Pet.new
end
# GET /pets/1/edit
def edit
end
# POST /pets
# POST /pets.json
def create
#pet = Pet.new(pet_params)
respond_to do |format|
if #pet.save
format.html { redirect_to #pet, notice: 'Pet was successfully created.' }
format.json { render :show, status: :created, location: #pet }
else
format.html { render :new }
format.json { render json: #pet.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /pets/1
# PATCH/PUT /pets/1.json
def update
respond_to do |format|
if #pet.update(pet_params)
format.html { redirect_to #pet, notice: 'Pet was successfully updated.' }
format.json { render :show, status: :ok, location: #pet }
else
format.html { render :edit }
format.json { render json: #pet.errors, status: :unprocessable_entity }
end
end
end
# DELETE /pets/1
# DELETE /pets/1.json
def destroy
#pet.destroy
respond_to do |format|
format.html { redirect_to pets_url, notice: 'Pet was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pet
#pet = Pet.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def pet_params
params.require(:pet).permit(:name, :type)
end
end
Model:
class Pet < ActiveRecord::Base
end
Rename your column "type" to "pet_type" or something else.
type is used by rails for single table inheritance.
STI is basically the idea of using a single table to reflect multiple models that inherit from a base model, which itself inherits from ActiveRecord::Base. In the database schema, sub-models are indicated by a single “type” column. In Rails, adding a “type” column in a database migration is sufficient (after writing the models) to let Rails know that you’re planning to implement STI

param is missing or the value is empty: module_list

I'm trying to enter a list of new modules and when I press 'new module list' which should take me to the form to fill out it throws up the error from the title. The application trace points at the bottom, the code inside 'def module_list_params' and also just above it where 'def set_student' is. I have no idea why it's doing it. I'm using ruby on rails.
class ModuleListsController < ApplicationController
before_action :set_module_list, only: [:show, :edit, :update, :destroy]
before_action :set_student, only: [:new, :create]
# GET /module_lists
# GET /module_lists.json
def index
#module_lists = ModuleList.all
end
# GET /module_lists/1
# GET /module_lists/1.json
def show
end
# GET /module_lists/new
def new
#module_list = #student.module_lists.new
end
# GET /module_lists/1/edit
def edit
end
# POST /module_lists
# POST /module_lists.json
def create
#module_list = #student.module_lists.new(module_list_params)
respond_to do |format|
if #module_list.save
format.html { redirect_to #module_list, notice: 'Module successfully created.' }
format.json { render :show, status: :created, location: #module_list }
else
format.html { render :new }
format.json { render json: #module_list.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /module_lists/1
# PATCH/PUT /module_lists/1.json
def update
respond_to do |format|
if #module_list.update(module_list_params)
format.html { redirect_to #module_list, notice: 'Module list was successfully updated.' }
format.json { render :show, status: :ok, location: #module_list }
else
format.html { render :edit }
format.json { render json: #module_list.errors, status: :unprocessable_entity }
end
end
end
# DELETE /module_lists/1
# DELETE /module_lists/1.json
def destroy
#module_list.destroy
respond_to do |format|
format.html { redirect_to module_lists_url, notice: 'Module list was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_module_list
#module_list = ModuleList.find(params[:id])
end
def module_list_params
params.require(:module_list).permit(:student_id, :title, :description, :credit_value)
end
def set_student
#student = Student.find_by(id: params[:student_id]) ||
Student.find(module_list_params[:student_id])
end
end
Rake routes screenshot
I believe your issue is the line before_action :set_student, only: [:new, :create]. set_student is being run when you go to the page with the form, but since there is no student_id included in the URL, it can't find anything to set it to.
To create a dependent object, there are two main ways: you can either have a form page tied to a specific parent object already, ie /students/4/module_lists/new, in which case submitting the form will create a module list tied to the student with an ID of 4. The other way is to have a general form not tied to any specific parent object, with some way of selecting a parent inside the form, eg a select or something. In that case the url would just be something like /module_lists/new.
If you want to go the first route, you'll want to nest the resources :module_lists inside of students. Check out the docs for how to do that, but it would basically look like
resources :students do
resources :module_list
end
And then in the link_to you click to go to that page, you'll need to pass in the student_id:
link_to 'Create Module List', new_student_module_list_path(#student)
For the second option, you can just remove :new from the before_action, change the new method to
def new
#module_list = ModuleList.new
end
And then add a way of picking which student to tie it to to the form.

Rails URL routing and grouping posts based on topic

I am new to rails I created post model and posts_controller which has Name:string, EMail:string, Message:text, topic_id:integer columns using scaffold.
I also created a topic model and topics_controller which has Topic_Name:string in it.
I provided the relationship among the models as follows:
class Topic < ActiveRecord::Base
has_many :posts, foreign_key: 'topic_id'
end
class Post < ActiveRecord::Base
belongs_to :topic
end
In routes.db I created the nested resources as:
resources :topics do
resources :posts
end
topics_controller.rb code:
class TopicsController < ApplicationController
before_action :set_topic, only: [:show, :edit, :update, :destroy]
# GET /topics
# GET /topics.json
def index
#topics = Topic.all
end
# GET /topics/1
# GET /topics/1.json
def show
end
# GET /topics/new
def new
#topic = Topic.new
end
# GET /topics/1/edit
def edit
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(topic_params)
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render :show, status: :created, location: #topic }
else
format.html { render :new }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /topics/1
# PATCH/PUT /topics/1.json
def update
respond_to do |format|
if #topic.update(topic_params)
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { render :show, status: :ok, location: #topic }
else
format.html { render :edit }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url, notice: 'Topic was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_topic
#topic = Topic.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def topic_params
params.require(:topic).permit(:Name)
end
end
posts_controller code:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
def new
#post = Post.new
end
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:Name, :Email, :Message, :topic_id)
end
end
I need to group posts using the topic. i.e., On clicking show on a particular topic it should go to the URL /topics/<topic_id>/posts where it should lists all posts related to that topic and I can create/delete posts belongs to that topic.
Can anyone help doing this..
Thank you..
Your question should be more direct, there's a lot of information that aren't related to the problem (the attributes names, for example), and your goal isn't clear enough.
It seems that you just want to setup the routes, right? You already have all posts related to that topic though the association: topic.posts. You just need to setup nested resource routes for posts:
resources :topics do
resources :posts
end
Also, you don't need the foreign_key option since you're using the naming conventions. It seems as well that you named some attributes in upper case, they should be name, email and message.
UPDATE:
In the index action, since you want posts belonging to one topic, you need to scope the #posts instance variable. Since you're using nested resources, you have the parameter params[:topic_id], so just fetch the topic with #topic = Topic.find(params[:topic_id]), then scope the association with #posts = #topic.posts. You'll need to do the same for every other action. I recommend that you read a little about associations in Rails, you'll probably need to use methods like #topic.posts.build and #topic.posts.find(params[:id]).
I found the solution for this problem in this link: Nested resources
Download the source code and find the solution...

Getting the ID of a Model that Uses Nested Routes and Permalinks in Rails

So I had my app set up with ids like so:
resources :studios do
resources :bookings
end
This gave me the route to the index (which later I'm going to use json for to get calendars for each studio.
studio_bookings GET /studios/:studio_id/bookings(.:format) bookings#index
This is good, but I wanted to get rid of the ID and use a permalink instead, just for a friendlier URL.
Change to:
namespace :studio, :path =>'/:permalink' do
resources :bookings
end
Now I'm getting
studio_bookings GET /:permalink/bookings(.:format) studio/bookings#index
Great! this is how I want my url to look, however, now the :id isn't anywhere in the route so... I get
Couldn't find Booking without an ID
It isn't even being passed. Is there a way to pass the :id in with the url without it being actually USED in the url? Otherwise, do I change the primary key from :id to :permalink in order to fix this?
I tried changing my controller from
#studio = Studio.find(params[:id])
to
#studio = Studio.find(params[:permalink])
but that gives me
Couldn't find Booking with 'id'=40frost
Which tells me what I'm doing isn't really meant to be done? It's trying to put the permalink as the id, so even though I'm telling rails to look for the permalink, it's still seemingly looking it up as an ID.
Hopefully my problem is clear: essentially - how can I pass the id so it knows which studio without displaying it in the URL. If there's some controller magic I can do instead that would be convenient.
Here's my controller for good measure
class Studio::BookingsController < ApplicationController
before_action :set_booking, only: [:show, :edit, :update, :destroy]
# GET /bookings
# GET /bookings.json
def index
#studio = Studio.find(params[:permalink])
#bookings = Booking.where("studio_id => '#studio.id'")
end
# GET /bookings/1
# GET /bookings/1.json
def show
end
# GET /bookings/new
def new
#booking = Booking.new
end
# GET /bookings/1/edit
def edit
end
# POST /bookings
# POST /bookings.json
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: 'Booking was successfully created.' }
format.json { render action: 'show', status: :created, location: #booking }
else
format.html { render action: 'new' }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /bookings/1
# PATCH/PUT /bookings/1.json
def update
respond_to do |format|
if #booking.update(booking_params)
format.html { redirect_to #booking, notice: 'Booking was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
# DELETE /bookings/1
# DELETE /bookings/1.json
def destroy
#booking.destroy
respond_to do |format|
format.html { redirect_to bookings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_booking
#booking = Booking.find(params[:permalink])
end
# Never trust parameters from the scary internet, only allow the white list through.
def booking_params
params.require(:booking).permit(:start_time, :end_time, :studio_id, :engineer_id, :title, :allDay)
end
end
You could just do
self.primary_key = 'permalink'
in your Studio model, or you could do
def index
#studio = Studio.find_by permalink: params[:permalink]
#bookings = Booking.where(studio_id: #studio.id)
end
depends if you just want to locally change the behavior or adress the Studio model by permalink always.
Hope that helps!

Rails Friendly Id - Couldn't find Category with id=electronics

I'm trying to develop a app in Ruby on Rails 4.0 (already used older versions of this incredible framework) and I having some troubles.
I installed the FriendlyID gem and I think everything is okay, but I'm receiving errors when I try to test my app.
If I go to http://0.0.0.0:3000/categories/1, this works. But when I click in "edit" in this page, or just go to http://0.0.0.0:3000/categories/electronics (that's the slugged name of category with ID 1), I receive the following error:
Couldn't find Category with id=electronics
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id]) #Here's pointed the error
end
Category Model:
class Category < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
# Validations
validates_uniqueness_of :name, :case_sensitive => false
end
Category Controller:
(generated by scaffold for test purposes)
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
# GET /categories
# GET /categories.json
def index
#categories = Category.all
end
# GET /categories/1
# GET /categories/1.json
def show
end
# GET /categories/new
def new
#category = Category.new
end
# GET /categories/1/edit
def edit
end
# POST /categories
# POST /categories.json
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render action: 'show', status: :created, location: #category }
else
format.html { render action: 'new' }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /categories/1
# PATCH/PUT /categories/1.json
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# DELETE /categories/1
# DELETE /categories/1.json
def destroy
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:name)
end
end
Migration:##
(I added friendlyId after create the Category table, but I think is okay)
class AddColumnToCategory < ActiveRecord::Migration
def change
add_column :categories, :slug, :string
add_index :categories, :slug, unique: true
end
end
Routes:
resources :categories
Hope you can help me. What I'm doing wrong in Rails 4.0?
Check the doc, friendly id stopped hacking find method (for the greater good), you now have to do:
# Change Category.find to Category.friendly.find in your controller
Category.friendly.find(params[:id])
You can now use:
extend FriendlyId
friendly_id :name, use: [:finders]
in your model.

Resources