I am trying to have a drop down from the other model and display its name in the index page
I have a 3 tables "students", "classrooms", and "classroom_students"
what I am trying is when a student is created he should be able to add the classroom from a dropdown which is populated from classroom table, at the moment the drop down is working however it is getting the id from the dropdown
How to get the classroom name to display in index page
classroom model
class Classroom < ApplicationRecord
belongs_to :user
has_many :classroom_students
has_many :students, through: :classroom_students
end
student model
class Student < ApplicationRecord
has_many :classroom_students
has_many :classrooms, through: :classroom_students
validates :student_fname, presence: true, length: { minimum: 3, maximum: 50 }
end
classroom_student model
class ClassroomStudent < ApplicationRecord
belongs_to :classroom
belongs_to :student
end
students controller
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender, :dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id, :group_id, :active)
end
classrooms controller
def classroom_params
params.require(:classroom).permit(:classroom_name, :classroom_year, :classroom_student)
end
students views form
<%= form.select :classroom_id, Classroom.where(:user_id => current_user.id).map {|r| [r.classroom_name, r.id]} %>
student index
at the moment it is id but I want it to be classroom name
<td><%= student.classroom_id %>
Schema file
create_table "classroom_students", force: :cascade do |t|
t.integer "classroom_id"
t.integer "student_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "classrooms", force: :cascade do |t|
t.string "classroom_name"
t.date "year"
t.string "classroom_student"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "users_id"
t.integer "user_id"
t.string "classroom_year"
t.index ["users_id"], name: "index_classrooms_on_users_id"
end
create_table "students", force: :cascade do |t|
t.string "student_fname"
t.string "student_lname"
t.boolean "gender"
t.string "dob"
t.boolean "aboriginal"
t.boolean "esl"
t.text "special_provisions"
t.integer "user_id"
t.integer "classroom_id"
t.integer "group_id"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "classroom_name"
end
Your association says that student has many classrooms but your database schema says you have a clasroom_id too in the students table. Remove that classroom_id first if you need to associate a student to multiple classrooms. Then your select says:
<%= form.select :classroom_id, Classroom.where(:user_id => current_user.id).map {|r| [r.classroom_name, r.id]} %>
Now as you have multiple classrooms associated to one student so this will not work because classroom_id is not valid. Instead it should be like this:
<%= f.select :classroom_ids, Classroom.where(user_id: current_user.id).map { |r| [r.classroom_name, r.id] }, {}, multiple: true %>
This will associate multiple classrooms with the student.
And donot forget to add classroom_ids in strong params:
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender, :dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id, :group_id, :active, :classroom_ids => [])
end
Hope this helps.
First of all, you have an association User has_many :classrooms, so you can't think that you only have 1 classroom.
You can get all the classes associated to an user with something like this:
<%= f.form_for #student do |f| %>
<%= f.collection_select(:classrrom_id, Classroom.all, :id, :classroom_name,
{:prompt => "Select your classrooms"}, {:multiple => true}) %>
<% end %>
And at your students_controller.rb you should add classroom_ids to your params
def student_params
params.require(:student).permit(:student_fname, :student_lname, :gender,
:dob, :aboriginal, :esl, :special_provisions, :user_id, :classroom_id,
:group_id, :active, :classroom_ids => [])
end
Related
I have a poll and a poll has questions. These are the models:
class poll < ApplicationRecord
validates_presence_of :user, :title, :URL, :poll_type, :start_date, :end_date
belongs_to :user
has_many :questions, dependent: :destroy
end
class Question < ApplicationRecord
validates_presence_of :poll_id, :question_type, :title
belongs_to :poll
end
The schema for polls is as follows
create_table "polls", force: :cascade do |t|
t.bigint "user_id", null: false
t.string "title"
t.text "description"
t.text "URL"
t.string "poll_type"
t.datetime "start_date"
t.datetime "end_date"
t.boolean "weighted_voting"
t.boolean "show_results"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_polls_on_user_id"
end
The schema for quesitons
create_table "questions", force: :cascade do |t|
t.bigint "poll_id", null: false
t.string "question_type"
t.string "title"
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["ballot_id"], name: "index_questions_on_ballot_id"
end
my routes.rb
resources :users do
resources :polls do
resources :questions do
resources :options
end
end
end
How can the user create a new instance of a question from their assigned given poll?
Currently the field poll_id in the questions form is empty. I can't figure out how to get this id populate. the polls form gets the user_id from devise's current_user.id variable via a form.
Also is doing this via the form the rails correct way of doing it?
Bonus Question: Would the method be the same for the options model?
You can do this by nested forms.
Details are here
Firstly you should create new pool form. Basically this form must include Poll and Question form fields. You must use fields_for helper to create related forms for specific model.
poll form
<%= form_for #poll do |poll| %>
Poll name: <%= poll.text_field :poll_name%>
<%= fields_for :question, #poll.questions do |question_fields| %>
Question 1 : <%= question_fields.text_field :question_1 %>
Answer 1 : <%= question_fields.check_box :answer_1 %>
Answer 2 : <%= question_fields.check_box :answer_2 %>
Answer 3 : <%= question_fields.check_box :answer_3 %>
<% end %>
<%= poll.submit %>
<% end %>
in model file
class Poll < ApplicationRecord
validates_presence_of :user, :title, :URL, :poll_type, :start_date, :end_date
belongs_to :user
has_many :questions, dependent: :destroy
accepts_nested_attributes_for :questions
end
in poll controller permit the question attributes
questions_attributes: [
:id,
:question_text,
:answer_1,
:answer_2,
...
:poll_id]
poll controller new action
5.times { #poll.questions.build }
info about routes
Rails docs says: Resources should never be nested more than 1 level deep.
You can solve your problem with only
resources :polls
All you need to do inject current_user to poll controller when saving form. You don't need to another resources for questions. You can show all questions under the poll show page.
Im currently trying to create a search form and everytime I try to send a request rails always report me the NoMethodError above. Below is my code.
controller
#search_cat = params['search_cat']
if #search_cat.present?
category_id = #search_cat['category_id']
#tasks = Task.where(user_id: current_user.id, category_id: category_id.to_i)
end
view
<%= simple_form_for :search_cat, url: tasks_index_path, method: "GET", html: { class: 'form-inline' } do |f| %>
<%= f.input :category_id, collection: current_user.categories,as: :select %>
<%= f.submit "Search", class: "btn btn-primary" %>
<% end %>
def tasks_params
params.require(:task).permit(:deadline_at,:title, :tags, :note, :is_done, :category_id, :user_id, {tag_ids: []})
end
edit:
class Task < ApplicationRecord
belongs_to :user, optional: true
belongs_to :category, optional: true
has_many :tag_associations, dependent: :destroy
has_many :tags, through: :tag_associations
end
schema
create_table "tasks", force: :cascade do |t|
t.datetime "deadline_at"
t.string "title"
t.string "note"
t.boolean "is_done"
t.integer "user_id"
t.integer "category_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["category_id"], name: "index_tasks_on_category_id"
t.index ["user_id"], name: "index_tasks_on_user_id"
I basiclly just trying send the input from the search form to query controller.
enter image description here
My guess would be that you don't have a category reference set in your task table. I would double check your schema to make sure you have all the columns within your task table match your params that you are permitting in your controller. Also make sure you have your relationships set within your models between your task model and category model.
I have a joined table but looking for a way to input the information from a form into both tables, or have it work in general:
My schema:
create_table "categories", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "categories_listings", id: false, force: :cascade do |t|
t.integer "category_id", null: false
t.integer "listing_id", null: false
end
create_table "listings", force: :cascade do |t|
t.string "name"
t.text "description"
t.decimal "price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
t.integer "user_id"
end
Models:
class Category < ApplicationRecord
has_and_belongs_to_many :listings
end
Listing < ApplicationRecord
belongs_to :category, required: false
belongs_to :categories_listings, required: false
end
Views
<%= form_with(model: listing, local: true) do |form| %>
...
<div class="space">
<%= form.select :category_ids, options_from_collection_for_select(Category.all, :id, :name), :prompt => "Select a Category", :multiple => true %>
</div>
...
Before i joined the tables, I had it working with a categories element (i believe thats the right term) within the listing tables that was attached to a categories table... You can see my previous post on SO where I was suggested to do this: Allowing multiple records in category to submit to listing
When i click submit, nothing enters into the categories_listings tables. Suggestions on how I make this happen?
The associations in your Listing model are wrong. It should be just
Listing < ApplicationRecord
has_and_belongs_to_many :categories
end
I suggest you to read has_and_belongs_to_many
Have a recipient and sender, both of the same class(Message) for a messaging system in rails. Want to set the params for both i.e. if user creates a message sender by default is the user_id and recipient will be the contact selected from the users contact list.
Currently the database is only receiving a user_id to the recipient_id column which is wrong and should be to sender_id column. Sender_id receives nothing.
After reading, some say not to amend the params as this is bad practice. So set a hidden field in the message view (like the body and title) yet this isn't pushing in to the database.
Two questions, is this process an appropriate rails practice? (ask this as new to rails) If not: can you advise another path or direction? If so: any ideas/thoughts why this isn't saving in to the database?
user model
class User < ActiveRecord::Base
has_many :messages, class_name: "Message", foreign_key: "recipient_id"
has_many :sent_messages, class_name: "Message", foreign_key: "sender_id"
has_many :contacts, dependent: :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
validates_presence_of :firstname, allow_blank: false
validates_presence_of :surname, allow_blank: false
end
message model
class Message < ActiveRecord::Base
belongs_to :sender, class_name: "User", foreign_key: "sender_id"
belongs_to :recipient, class_name: "User", foreign_key: "recipient_id"
validates_presence_of :body, :title
end
Messages controller
class MessagesController < ApplicationController
before_action :message, only: [:show]
before_action :authenticate_user!
def index
#messages = current_user.messages
end
def new
#message = Message.new
end
def create
current_user.messages.create(message_params)
redirect_to '/messages'
end
def show
end
private
def message_params
params.require(:message).permit(:title, :body, :sender_id, :recipient_id)
end
def message
#message = Message.find(params[:id])
end
end
message/new view
<%= form_for #message do |f| %>
<%= hidden_field_tag :sender_id, current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
schema
ActiveRecord::Schema.define(version: 20160517131719) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "contacts", force: :cascade do |t|
t.string "firstname"
t.string "surname"
t.string "email"
t.integer "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.integer "user_id"
end
add_index "contacts", ["user_id"], name: "index_contacts_on_user_id", using: :btree
create_table "messages", force: :cascade do |t|
t.string "title"
t.text "body"
t.integer "sender_id"
t.integer "recipient_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "firstname"
t.string "surname"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
add_foreign_key "contacts", "users"
end
Try changing your form to this:
<%= form_for #message do |f| %>
<%= f.hidden_field :sender_id, value: current_user.id %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
Currently the database is only receiving a user_id to the recipient_id
column which is wrong and should be to sender_id column.
In your create action, you have current_user.messages.create(message_params). This creates a message record in the DB with the foreign key's(i.e, recipient_id in your case) value with the parent's(user) id. This is the reason, the recipient_id gets the value of user's id.
Sender_id receives nothing.
This is because the hidden_field set for sender_id is not wrapped with the form builder instance. You need to change
<%= hidden_field_tag :sender_id, current_user.id %>
to
<%= f.hidden_field :sender_id, current_user.id %>
I've got a really weird problem with my project. I've got 2 models, the one is Link and the other Category. I've got a index view where all the links should be listed, together with the corresponding category names. When running the server and trying to use
<%= link.category.name %>
I get an error page with the following:
undefined method `name' for nil:NilClass
But when I open the console and write:
link = Link.find(1) #there is currently only one link
link.category.name
It returns the correct category name.
Here are my Models and schema.rb:
class Link < ActiveRecord::Base
attr_accessible :category_id, :description, :title, :url, :visible
belongs_to :category
scope :visible, lambda { where(visible: true) }
end
.
class Category < ActiveRecord::Base
attr_accessible :name
has_many :links
end
.
ActiveRecord::Schema.define(:version => 20130420070717) do
create_table "categories", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "categories", ["id"], :name => "index_categories_on_id"
create_table "links", :force => true do |t|
t.string "title"
t.text "description"
t.string "url"
t.integer "category_id"
t.boolean "visible"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "links", ["category_id"], :name => "index_links_on_category_id"
add_index "links", ["id"], :name => "index_links_on_id"
end
How can this happen? Thank you very much for your help!
Maybe I can help others facing the same issue.
The category_id was assigned to the link by a form which queries the existing categories from the db.
<%= f.select(:category_id, #categories.collect { |c| c.name }) %>
The category I wanted to assign has the id = 1. After selecting the category from the dropdown menu, the link.category_id was 0, it should have been 1.
UPDATE:
I fixed the wrong index by:
<%= f.collection_select :category_id, #categories, :id, :name, :prompt => "Select a category" %>