What I'd like to do is to display the name in the details table.
I tried some codes, but I couldn't.
Please advise me on how to display the value.
Controller code:
class BooksController < ApplicationController
def show
#book = Book.find(params[:id])
#article = Article.where(book_id: (params[:id])).order(day: :asc)
end
end
View code:
<div class="row">
<% #article.each do |a| %>
<%= a.day %><br>
<%= a.title %><br>
# want to display the name in detail table where (details.day = articles.day and details.book_id = articles.book_id)
<% end %>
</div>
Relevant model setup:
class Article < ActiveRecord::Base
belongs_to :Book
default_scope -> { order(day: :asc, start_time: :asc) }
end
class Detail < ActiveRecord::Base
belongs_to :Book
end
class Book < ActiveRecord::Base
has_many :articles
has_many :details
end
Schema:
ActiveRecord::Schema.define(version: 2015099999999) do
create_table "details", force: true do |t|
t.integer "book_id"
t.integer "day"
t.string "name"
t.string "detail"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "articles", force: true do |t|
t.integer "book_id"
t.integer "day"
t.string "start_time"
t.string "end_time"
t.integer "category"
t.string "title"
t.string "contents"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "books", force: true do |t|
t.date "publish_date"
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
end
end
You want to define an association between Article and Detail using the :through option:
class Article < ActiveRecord::Base
belongs_to :book
has_many :details, through: :book
end
You can also define an accessor to find just the detail for the matching day:
class Article < ActiveRecord::Base
def matching_detail
details.find_by_day day
end
end
Which you can then use in the view:
<% #article.each do |a| %>
<%= a.matching_detail.try(:name) %>
<% end %>
It's good to define the associations for articles like
has_many :details, through: :book
You can also also use this .
Article.includes(:details).where(book_id: (params[:id])).order(day: :asc)
Or
Article.select('articles.name,details.name,..').joins(:details).where([condition])
Related
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
In my ruby on rails application i've applied a relationship between two table: Article and Category with a relation has_and_belongs_to_many.
class Category < ActiveRecord::Base
has_and_belongs_to_many :articles
end
class Article < ActiveRecord::Base
has_and_belongs_to_many :categories
end
I'm following this tutorial for implement a Has_many system with the checkboxes (Railcast)
i've write this part:
<% for category in Category.all%>
<div>
<%= check_box_tag "article[category_ids][]", category.id, #article.categories.include?(category) %>
<%= category.name %>
</div>
<% end %>
but i've got this error :
Mysql2::Error: Table 'CMS_development.articles_categories' doesn't exist: SHOW FULL FIELDS FROM articles_categories
Where am i wrong?
EDIT ADDING THE MIGRATION AND THE SCHEMA
MIGRATION:
class AddCategoryToArticles < ActiveRecord::Migration
def change
add_reference :articles, :category, index: true, foreign_key: true
end
end
SCHEMA:
ActiveRecord::Schema.define(version: 20151001153131) do
create_table "articles", force: :cascade do |t|
t.boolean "published"
t.boolean "on_evidance"
t.boolean "foreground"
t.string "title", limit: 255
t.string "subtitle", limit: 255
t.datetime "date"
t.text "body", limit: 65535
t.text "small_body", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "category_id", limit: 4
end
add_index "articles", ["category_id"], name: "index_articles_on_category_id", using: :btree
create_table "categories", force: :cascade do |t|
t.string "name", limit: 255
t.text "description", limit: 65535
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "articles", "categories"
end
Two issues:
You don't have the join table articles_categories
You're not referencing the categories correctly
Firstly, to use a has_and_belongs_to_many association, you need to invoke the appropriate join table:
Your schema shows, quite clearly, that you don't have this. As stated in other answers, you need to create a schema as follows:
class CreateArticlesCategories < ActiveRecord::Migration
def change
create_table :articles_categories, id: false do |t|
t.references :articles
t.references :categories
end
end
end
This will give you the join table which you'll be able to populate with your select box...
--
For your checkbox, you can do the following:
#app/views/articles/new.html.erb
<%= form_for #article do |f| %>
<%= f.collection_select :categories, Category.all, :id, :name %>
<%= f.submit %>
<% end %>
To populate this through the controller, you'd need to use the following:
#app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def create
#article = Article.new article_params
#article.save
end
private
def article_params
params.require(:article).permit(:title, :categories)
end
end
You should write and execute a migration for creating articles_categories table:
class CreateArticleCategory < ActiveRecord::Migration
def change
create_table :articles_categories do |t|
t.references :articles
t.references :categories
end
end
end
So, I have 3 models Quotes, Categories, and Subscribers.
Essentially, it's a newsletter application. Subscribers can select a category and then enter their email and they will receive quotes related to that category via email.
There's two issues here,
1. The category's are stored in a constant in the category model.
so how do I display the category type that the subscriber chose
in text format? I'd like to show in the email
something like "here's your email on <%= category.name %>" which would translate to
"here's your email on Food."
2. I'd like to ONLY send emails about the category that the subscriber subscribed to.
How might I accomplish this? Please provide examples.
This is what I have so far:
Category.rb
class Category < ActiveRecord::Base
belongs_to :quote
belongs_to :subscriber
CATEGORY_TYPE = {
1 => "Food",
2 => "Fitness",
3 => 'Cats',
}
end
Quote.rb
class Quote < ActiveRecord::Base
has_many :categories
belongs_to :category
validates :title, presence: true
end
Subscriber.rb
class Subscriber < ActiveRecord::Base
has_one :category
validates :email, presence: true
end
schema
create_table "categories", force: true do |t|
t.string "name"
t.integer "quote_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "subscriber_id"
t.integer "category_type"
end
create_table "quotes", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "subscribers", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
end
Update subscribers_mailer.rb
def SendMyEmail(email, category, quote, subscribers)
#category = category
#quote = quote
#subscribers = subscribers
#email = email
mail to: email, subject: 'New Quotes'
end
end
and then of course:
Category.all.each do |category|
SubscriptionMailer.SendMyEmail("email#test.com", category, category.quotes.first, category.subscribers).deliver
end
Update:
There's two remaining issues here,
1. Categories aren't syncing to subscribers. For example when I run category.subscribers.last
it's nil. and category.subscribers throws an empty array. How can I sync these? I think it has
to do with the fact that subscribers are selecting a category from the Category::CATEGORY_TYPES
constant as seen in the view code below.
2. I'd like to automate it so that these emails are sent to subscribers once a day.
How might I do this?
view code (subscribers/new.html.erb:
<div class="styled email-input2">
<%= form_for #subscriber do |f| %>
<% if #subscriber.errors.any? %>
<div class="errorExplanation" style="color: white;">
<h2><%= pluralize(#subscriber.errors.count, 'error') %> encountered:</h2>
<ul>
<% #subscriber.errors.full_messages.each do |m| %>
<li><%= m %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.fields_for :subscriber, #subscriber.build_category do |cat| %>
<%= cat.select(:category_type, Category::CATEGORY_TYPE.map{|p| [p[1], p[0]]}, {prompt: 'Please select'}, {class: 'styled email-input2'}) %>
<% end %>
</div>
Ok first lets modify the migrations:
create_table "categories", force: true do |t|
#DELETE QUOTE_ID AND SUBSCRIBER ID
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "category_type"
end
create_table "quotes", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.references :category #this will add integer category_id
end
create_table "subscribers", force: true do |t|
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
t.references :category #this will add integer category_id
end
Next we will modify the models to reflet the changes in the migration:
class Category < ActiveRecord::Base
has_many :quotes
has_many :subscribers
CATEGORY_TYPE = {
1 => "Food",
2 => "Fitness",
3 => 'Cats',
}
end
class Quote < ActiveRecord::Base
belongs_to :category
validates :title, presence: true
end
class Subscriber < ActiveRecord::Base
belongs_to :category
validates :email, presence: true
end
Now you can get the subscribers for a cateogyr using the following:
category = Category.find(1) #use whatever id you want
category.subscribers #list of all subscribers for a category
Getting the quotes for a category is similarly straight forward:
category = Category.find(1)
category.quotes
So assuming your mailer takes a category, quote and a list of subscribers for the email to send
Category.all.each do |category|
Mailer.SendMyEmail(category, category.quotes.first, category.subscribers).deliver
end
In the "SendMyEmail" function in your mailer you will have
def SendMyEmail(category, quote, subscribers)
#YOUR CODE FOR TYHE VIEW HERE
end
I'm trying to set up a simple search from one view through a joined table and, being a newbie, it's not quite working. I'm testing with the word "books" which I know is in the articles table in the subject column.
My error is:
SQLite3::SQLException: no such column: articles.subject: SELECT COUNT(*) FROM "keywords" WHERE (articles.subject LIKE '%books%')
My schema is:
create_table "articles", force: true do |t|
t.string "title"
t.string "subject"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "articles_keywords", id: false, force: true do |t|
t.integer "article_id"
t.integer "keyword_id"
end
create_table "keywords", force: true do |t|
t.string "keyword"
t.datetime "created_at"
t.datetime "updated_at"
end
My model is:
class Keyword < ActiveRecord::Base
has_and_belongs_to_many :articles
accepts_nested_attributes_for :articles
def self.search_for(query)
where('articles.subject LIKE :query', :query => "%#{query}%")
end
My controller action is:
def index
#keywords = params[:q] ? Keyword.search_for(params[:q]) : Keyword.all
end
My view action is:
<%= form_tag "/", method: "GET" do %>
<%= text_field_tag :q %>
<%= submit_tag "Search" %>
<% end %>
<% if #keywords.any? %>
<% #keywords.each do |k| %>
<section>
<h3><b>Title</b>: <%= link_to k.keyword.title, keyword.title %></h3>
<p><b>Subject</b>: <%= keyword.subject%></p>
<% end %>
Many thanks for any help!
You have to join the asocciated table (and you can use scopes):
class Keyword < ActiveRecord::Base
has_and_belongs_to_many :articles
accepts_nested_attributes_for :articles
scope :search_for, ->(query){ joins(:acticles).where('articles.subject LIKE :query', :query => "%#{query}%")}
end
See RubyOnRails-Guides
A gem that eases complex querying is squeel. With squeel the scope would by
scope :search_for, ->(query){ joins{articles}.where{articles.subject =~ "%#{query}%"} }
if you go to www.leapfm.com you'll see each song has a youtube url in parenthesis to the right of it. After gauging feedback I have decided to instead display the genre tags in the parenthesis.
When trying to do this,
I'm getting this error:
Couldn't find Genre without an ID
Extracted source:
def genre_name
#genre = Genre.find(params[:id])
end
def get_last_song
song_controller snippit
def index
if params[:query].present?
#songs = Song.search(params)
get_last_song
genre_name
elsif params[:genre]
#songs = Song.tagged_with(params[:genre]).paginate(:page => params[:page], :per_page => 15)
get_last_song
genre_name
else
#songs = Song.order('id').order('plusminus desc nulls last').paginate(:page => params[:page], :per_page => 15)
##songs = Song.tally.paginate(:page => params[:page], :per_page => 15)
get_last_song
genre_name
end
end
def genre_name
#genre = Genre.find(params[:id])
end
index.html.erb (_song partial) snippit
<div class="title">
<%=link_to image_tag('arrow.gif'), vote_for_song_path(song), :remote => true, :method => :put if controller.action_name == "index" %>
<%= link_to song.title, song %><span class="subtext"> (<%= song.genre_name %>)</span>
</div>
song.rb snippit:
class Song < ActiveRecord::Base
acts_as_voteable
belongs_to :user
has_many :comments, :dependent => :destroy
has_many :genre_songs
has_many :genres, through: :genre_songs
genre.rb
class Genre < ActiveRecord::Base
has_many :genre_songs, :dependent => :destroy
has_many :songs, through: :genre_songs
end
schema snippit
create_table "genre_songs", force: true do |t|
t.integer "genre_id"
t.integer "song_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "genre_songs", ["genre_id"], name: "index_genre_songs_on_genre_id", using: :btree
add_index "genre_songs", ["song_id"], name: "index_genre_songs_on_song_id", using: :btree
create_table "genres", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "songs", force: true do |t|
t.string "title"
t.string "artist"
t.text "url"
t.string "track_file_name"
t.string "track_content_type"
t.integer "track_file_size"
t.datetime "track_updated_at"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "plusminus"
end
You need to get rid off gendre_name method, as it doesn't give you what you want. You've assigned #songs to some list of songs, hence most likely somewhere in your view you have sth like:
<% #songs.each do |song| %>
# display song row
<% end %>
if so, use sth like below inside this each "loop":
(<%= song.genres.map(&:names).join(', ') %>)