I'm trying to implement an index view for questions where you can select a tag link to filter the questions to those with that tagging. I have a class method in Question where it returns only the tagged posts. Rails is giving me an error on the Tag class name in that method, although it works in the console.
None of the RecordNotFound questions on StackOverflow seem to be about referencing another class. Any advice on debugging this type of stuff or what could be going on?
I'm using Rails 5.2.0 and Ruby 2.4.2.
Error
ActiveRecord::RecordNotFound (Couldn't find Tag):
app/models/question.rb:13:in `tagged'
app/controllers/questions_controller.rb:6:in `index'
NameError: uninitialized constant Mime::HTML
Questions index.html.erb
<h2>Questions</h2>
<div class="row">
<div class = "tags">
<% Tag.all.each do |t| %>
<%= link_to t.name, questions_path(tag: t.name), class: 'badge badge-primary'%>
<% end %>
</div>
<% if current_user.customer? %>
<%= render "question" %>
<% else %>
<%= render "admin_question" %>
<% end %>
</div>
<div id="paginator">
<% #questions = #questions.page(params[:page]).per(10) %>
<%= paginate #questions, remote: true %>
</div>
Questions controller
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
def index
if params[:tag]
#questions = Question.tagged(:tag).page(params[:page]).per(10)
else
#questions = Question.page(params[:page]).per(10)
end
end
Models
class Question < ActiveRecord::Base
validates_presence_of :body
has_many :answers
has_many :users, through: :answers
has_many :taggings
has_many :tags, through: :taggings
def to_s
self.body
end
def self.tagged(tag)
Tag.find_by_name!(tag).questions
end
end
class Tagging < ApplicationRecord
belongs_to :question
belongs_to :tag
end
class Tag < ApplicationRecord
has_many :taggings
has_many :questions, through: :taggings
end
If you look at the error you can see that it occurred in your controller on line 6.
The problem is with Question.tagged(:tag). Here you are filtering questions that are tagged with the tag :tag and you probably haven't created a tag with name :tag. I believe you wanted to filter questions that are tagged with a tag that is passed in params, so you should use Question.tagged(params[:tag]).
Related
I'm running Rails 6.0.3.2 and I want to render a partial passing a local variable to another controller view:
My routes:
Rails.application.routes.draw do
devise_for :users
root to: 'notebooks#index'
resources :notebooks, only: [:index, :new, :show, :create, :edit, :update, :destroy] do
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
collection do
get "list"
end
end
resources :tags
end
Notebook Model:
class Notebook < ApplicationRecord
has_one_attached :photo
validates :asin, presence: true, uniqueness: true
after_initialize :init
acts_as_list column: :position, add_new_at: :bottom
has_many :taggings
has_many :tags, through: :taggings
def init
self.edited ||= false
end
end
Tag Model
class Tag < ApplicationRecord
has_many :taggings
has_many :notebooks, through: :taggings
end
In Tag controller:
def index
#tags = Tag.all.order(created_at: :asc)
end
I tried to follow this guide and render the "index view" from Tags Controller on the "list view". The application finds the tags/_index.html file, but return the error undefined method `each' for nil:NilClass. Bellow my views code:
In app/views/notebooks/list.html.erb:
<%= render :partial => "tags/index" , locals: {tags: #tags}%>
In app/views/tags/_index.html.erb
<% tags.each do |tag| %>
<div>
<div class="d-flex">
<p><%= tag.id %></p>
<p><%= tag.name %></p>
</div>
<p>tag.taggings.count</p>
</div>
<% end %>
Anyone can point me what i'm doing wrong? I read the Layouts and Rendering in Rails documentation, but i don't have a clue why the instructions won't work on my project...
Thanks in advance!
The rails way to do this is just to create a partial for a single record:
# app/views/tags/_tag.html.erb
<div>
<div class="d-flex">
<p><%= tag.id %></p>
<p><%= tag.name %></p>
</div>
<p>tag.taggings.count</p>
</div>
You can then pass the collection to render and Rails will look up the partial and render it for each member in the collection:
<%= render #tags %>
This is short for:
<%= render partial: 'tag', collection: #tags %>
See Rendering Collections.
I'm trying to associate a relation betwen 1 patient with a consultation, but I'm getting a error:
Association :patient not found
In the model I have:
class Patient < ActiveRecord::Base
belongs_to :user
has_many :consultums, through: :patients
end
class Consultum < ActiveRecord::Base
belongs_to :patients
belongs_to :user
has_one :recetum
end
in the controller I have:
class ConsultationController < ApplicationController
before_action :authenticate_user!
before_action :set_consultum, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#consultation = Consultum.all
respond_with(#consultation)
end
def show
respond_with(#consultum)
end
## when I try to create a new consultation, throw me the error ##
def new
#consultum = Consultum.new
# patient_id
respond_with(#consultum)
end
def edit
end
def create
#consultum = Consultum.new(consultum_params)
#consultum.save
respond_with(#consultum)
end
def update
#consultum.update(consultum_params)
respond_with(#consultum)
end
def destroy
#consultum.destroy
respond_with(#consultum)
end
# def patient_id
# patient = Patient.find(params[:id])
# # patient = #patient.id
# #consultum.patient_id = patient
# end
private
def set_consultum
#consultum = Consultum.find(params[:id])
end
def consultum_params
params.require(:consultum).permit(:Reason_Consultation, :Diagnostic, :TX, :Labs, :Observations, :patient_id)
end
end
so, as you can see I create the function patient_id, and I'm trying to retrieve the id from the 'patient' and put into patient_id in 'consultum' table, but seems not work...
if I uncomment patient_id function throw me this error:
Couldn't find Patient without an ID
I'm stuck, any idea?
Thanks in advance
EDIT
in my view I have:
consultation/new.html.erb
<div class="page-header">
<%= link_to consultation_path, class: 'btn btn-default' do %>
<span class="glyphicon glyphicon-list-alt"></span>
Back
<% end %>
<h1>New consultum</h1>
</div>
<%= render 'form' %>
_form.html.erb
<%= simple_form_for(#consultum) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :Reason_Consultation %>
<%= f.input :Diagnostic %>
<%= f.input :TX, placeholder: "optional" %>
<%= f.input :Labs, placeholder: "optional" %>
<%= f.input :Observations, placeholder: "optional" %>
<%= f.association :patient %>
</div>
<div class="form-actions">
<%= f.button :submit, "Save Consultation" %>
</div>
<% end %>
When creating associations in rails pay super close attention to the pluralization!
class Patient < ActiveRecord::Base
belongs_to :user
has_many :consultums, through: :patients
end
class Consultum < ActiveRecord::Base
belongs_to :patients
belongs_to :user
has_one :recetum
end
You will notice that your Consultum class does not have a patient relation. It has belongs_to :patients.
class Consultum < ActiveRecord::Base
belongs_to :patient
belongs_to :user
has_one :recetum
end
Also your attribute naming should follow the Ruby conventions!
Ruby uses snake_case for naming attributes and methods and will automatically treat any identifier which begins with an UPPERCASE letter as a constant!
This is not just a stylistic issue - MRI Ruby will let you reassign constants with a warning. Other versions or future versions may be less lenient.
Bad Good
.Reason_Consultation .reason_consultation
.Diagnostic .diagnostic
.TX .tx
.Lab .lab
.Observations .observations
https://github.com/bbatsov/ruby-style-guide
To call an action you can pass parameters as follow:
link_to "New Consultum", new_consultum_path(:id => here, yo have to put the paciente id)
Hope this helps!
I have microposts that belong to artists, and everything with that works perfectly.
Now I'm trying to let artists comment on microposts. However, this isn't working how I want it. The comments need to belong to both a specific artist and a specific micropost.
Right now I have a form to create a comment, but it only saves under the most recent micropost id.
### controllers/artists/comments_controller.rb ###
class Artists::CommentsController < ApplicationController
def create
#micropost = ArtistMicropost.find_by(params[:micropost_id])
#comment = #micropost.artist_micropost_comments.build(comment_params)
#comment.artist_id = current_artist.id
end
private
def comment_params
params.require(:artist_micropost_comment).permit(:artist_micropost_id, :artist_id, :content)
end
end
### controllers/artists/artists_controller.rb ###
class Artists::ArtistsController < ApplicationController
def show
#artist = Artist.find(params[:id])
#micropost = ArtistMicropost.new
#micro = ArtistMicropost.find_by(params[:micropost_id])
#comment = ArtistMicropostComment.new
end
end
### views/artists/show.html.erb ###
<% #artist.artist_microposts.each do |micropost| %>
...
<%= micropost.content %>
...
<% #micro.artist_micropost_comments.each do |comment| %>
<%= comment.content %>
<% end %>
<%= form_for(#comment) do |f| %>
<%= f.text_area :content %>
<%= f.submit "post comment" %>
<% end %>
<% end %>
### models/artist.rb ###
class Artist < ActiveRecord::Base
has_many :artist_microposts, dependent: :destroy
has_many :artist_micropost_comments, dependent: :destroy
end
### models/artist_micropost.rb ###
class ArtistMicropost < ActiveRecord::Base
belongs_to :artist
has_many :artist_micropost_comments, dependent: :destroy
end
### models/artist_micropost_comment.rb ###
class ArtistMicropostComment < ActiveRecord::Base
belongs_to :artist_micropost
belongs_to :artist
end
I want it to display each micropost by the artist and underneath each micropost to display the comments that belong to the micropost. I the want the from to display under the comments to add new comments. Basically, I want it to look something like Facebook.
Right now, all the comments are displaying under each micropost no matter what the micropost_id and the create method won't create under any micropost_id, except the most recent one.
So my two problems are:
I can't get the comments to save under the correct micropost_id
I can't get the comments to loop for their micropost.
Any ideas?
Short names are easier to read and understand so I will rename your models in my example to Artist, Micropost and Comment
class Artist < ActiveRecord::Base
has_many :microposts, dependent: :destroy
has_many :comments, through: :microposts, dependent: :destroy
end
class Micropost < ActiveRecord::Base
belongs_to :artist
has_many :comments, dependent: :destroy
end
class Comment < ActiveRecord::Base
# I renamed artist to commenter to make it clear that is not the same artist as the one that created the micropost,
# this implies that instead of author_id you will have commented_id in comments table
belongs_to :commenter, :class_name => Artist
belongs_to :micropost
end
### views/artists/show.html.erb ###
<% #artist.microposts.each do |micropost| %>
...
<%= micropost.content %>
...
<% micropost.comments.each do |comment| %>
# here you display comments for each micropost
<%= comment.content %>
# pay attention at the way I builded the comment
<%= form_for(micropost.comments.build) do |f| %>
<%= f.hidden_field :micropost_id %> # this will make the link to your micropost
<%= f.text_area :content %>
<%= f.submit "post comment" %>
<% end %>
<% end %>
<% end %>
In your comments_controller you must assign current logged in artist (the commenter) to your comment.
class CommentsController < ApplicationController
def create
#comment = Comment.new(comment_params)
#comment.commenter = current_artist
if #comment.save
...
end
end
private
def comment_params
params.require(:comment).permit(:micropost_id, :content)
end
end
To avoid N+1 when you load artists, microposts and commenters do something like this:
class ArtistsController < ApplicationController
def show
#artist = Artist.includes(:microposts, :comments => :commenter).find(params[:id])
end
end
For Your requirement. For creation of microposts.
do something like this.
artist=Artist who is logged in
artist.artist_micro_posts.build(attributes)
artist.save
For creating comments to microposts
micro_posts= Micropost Id
micro_post.artist_micropost_comments.build(:artist_id=logged in person)
micro_post.save
Okay, I have been banging my head against the wall for the past few hours trying to figure this out. I have a rails ecommerce app... the store lists products objects, and when you add the product to your cart (another object) it is added by creating a line_item object. When you are ready to checkout the line_items in your cart become an order. At this point, I am trying to allow the customer to provide a page_url (an outside website the product/service will be used on) [via a form_for text_field] to each line_item. To achieve this I created a new model called Page_url which belongs_to the order. Here is what I have that has been failing miserably (I keep getting Controller errors "undefined method `page_url'"):
here is the form:
<%= form_for(#order) do |f| %>
......
<% #items.each do |item| %>
<td><a> Provide the URL the <%= item.product.title %> will be added to</a></td>
<div class="field">
<%= f.fields_for #order, :page_url do |q| -%>
<td> <%= q.label :page_url %>
<%= q.text_field :page_url, size: 80 %>
</td>
<% end %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit t('.submit') %>
</div>
<% end %>
orders_controller:
class OrdersController < ApplicationController
skip_before_action :authorize, only: [:new, :create]
include CurrentCart
before_action :set_cart, only: [:new, :create]
skip_before_action :set_order, only: [:create, :update, :destroy]
......
# GET /orders/new
def new
if #cart.line_items.empty?
redirect_to store_url, notice: "Your cart is empty"
return
end
#items = #cart.line_items
#order = Order.new
#page_urls = #order.page_urls
end
.....
def order_params
params.require(:order).permit(:name, :address, :email, :pay_type,
:page_urls_attributes => [:page_url, :product_id,])
end
The Pages_url controller is the standard controller generated by Rails 4
Order.rb:
class Order < ActiveRecord::Base
has_many :line_items, dependent: :destroy
has_many :page_urls, dependent: :destroy
# ...
validates :name, :address, :email, presence: true
validates :pay_type, inclusion: PAYMENT_TYPES
accepts_nested_attributes_for :page_urls
Page_url.rb:
class PageUrl < ActiveRecord::Base
belongs_to :order
I appreciate any help, thanks
I usually use simple_form to create associations and it works great.
That way you can do <%= f.association :page_urls %>
They have great documentation, check here: https://github.com/plataformatec/simple_form under Associations.
Also another point:
In your Order model, I would specify the class.
has_many :page_urls, dependent: :destroy, :class_name => PageUrl
And to create nested forms with simple_form see:
https://github.com/plataformatec/simple_form/wiki/Nested-Models
Hope this helps!
When i try to submit the form below i get this error WARNING: Can't mass-assign protected attributes: sub_category.I have tried to go over previous asked related questions here on stackoverflow and seems like i am in the right track ,but for some reason i am still getting the same error,what am i doing wrong?.I have included all the info below, thank you in advance.
View/form
<%= form_for #ip ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :email %>
<% f.text_field :ip_address %>
<%= f.fields_for :sub_category do |s| %>
<%=s.text_field :name%>
<%end%>
<%=f.submit "submit" %>
<%end%>
Controller
def create
#ips=Ip.new(params[:ip])
#ip=#ips.sub_categories.build
if #ip.save
redirect_to :controller=>"home" ,:action=>"index"
else
render 'index'
end
Models
class Ip < ActiveRecord::Base
has_many :sub_categories ,:through=>:ip_subs
has_many :ip_subs
accepts_nested_attributes_for :sub_categories
attr_accessible :sub_categories_attributes,:ip_address,:email,:ip_count
end
class SubCategory < ActiveRecord::Base
has_many :ip ,:through=>:ip_subs
has_many :ip_subs
end
class IpSub < ActiveRecord::Base
belongs_to :ip
belongs_to :sub_category
end
You should use f.fields_for :sub_categories (association name).
And don't forget to build association before render the form:
# in controller
def new
#ip = Ip.new
#ip.sub_categories.build
end
rubyonrails api :: fields_for