no implicit conversion of nil into String Ruby on Rails - ruby-on-rails

can somebody help with this, please?
My blog post share isn't showing an image on Twitter. I benchmarked other websites and noticed all the blog post working websites had a domain URL in the prior to the image URL. So, I added on it and blog post started working!!!. Yayy
Then, I've encountered another problem. When I click to see a blog page, it shows an error message(per below)
ActionView::Template::Error (no implicit conversion of nil into String):
21: %meta{:content => "https://www.joynus.com"+#post.preview_image.try(:data).try(:url), :name => "twitter:image"}
My post controller
class PostsController < ApplicationController
before_filter :authorize, only: [:edit, :update, :new, :create, :destroy]
before_filter :find_post, only: [:show, :edit, :update, :destroy]
def index
#posts = Post.order("created_at DESC").page(params[:page]).per(9)
respond_to do |format|
format.html
format.rss { render :layout =>false }
end
end
def show
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to posts_url
else
render 'new'
end
end
def edit
end
def update
if #post.update_attributes(post_params)
redirect_to post_url(#post), notice: "#{#post.title} Updated"
else
render 'edit'
end
end
def destroy
#post.destroy
redirect_to posts_url, notice: "#{#post.title} Deleted"
end
private
def post_params
params.require(:post).permit(:title, :social_title, :contents, :author_id, :approved, :summary, :preview_image_id, :category)
end
def find_post
#post = Post.friendly.find(params[:id])
# If an old id or a numeric id was used to find the record, then
# the request path will not match the post_path, and we should do
# a 301 redirect that uses the current friendly id.
if params[:action] == 'show' && request.path != post_path(#post)
return redirect_to #post, :status => :moved_permanently
end
end
end
And, my post.rb
class Post < ActiveRecord::Base
extend FriendlyId
friendly_id :slug_candidates, use: [:slugged, :history]
belongs_to :preview_image, class_name: 'Ckeditor::Picture'
belongs_to :author, class_name: 'User'
## Validations
validates :contents, presence: true
validates :title, presence: true
validates :social_title, presence: true
validates :summary, presence: true, length: 1..300
validates :author, presence: false
validates :category, presence: true
delegate :full_name, to: :author, prefix: true, allow_nil: false
## Instance Methods
def slug_candidates
[
:slug_title,
[:id, :slug_title]
]
end
def slug_title
title&.downcase
end
def should_generate_new_friendly_id?
title_changed?
end
def raw_post
self.contents.html_safe
end
def preview_image_thumb(dimensions = '100x')
preview_image.try(:data).try(:thumb, dimensions).try(:url)
end
def self.preview_image_dimensions
'350x'
end
end
Is there a way to skip this error message? I did some research and found begin/rescue. But I don't know how and where to put it.
It would really appreciate any help or advice.

This is because you are using + to implicitly concatenate the URL to your host, but at least for one post, #post.preview_image.try(:data).try(:url) is returning as nil.
You could fix it by using string interpolation like this:
%meta{:content => "https://www.joynus.com#{#post.preview_image.try(:data).try(:url)}", :name => "twitter:image"}
Or by explicitly converting to string with to_s like this:
%meta{:content => "https://www.joynus.com"+#post.preview_image.try(:data).try(:url).to_s, :name => "twitter:image"}

Related

Updating a referenced entity through the create form of another

I have 2 models that are linked through a joint table:
class Dailyreport < ApplicationRecord
max_paginates_per 9
belongs_to :owner
has_many :dailyreport_issues
has_many :issues, through: :dailyreport_issues
accepts_nested_attributes_for :issues, allow_destroy: true
end
class Issue < ApplicationRecord
belongs_to :project
belongs_to :owner
has_many :dailyreport_issues
has_many :dailyreports, through: :dailyreport_issues
max_paginates_per 10
before_create { |issue| issue.jiraid = issue.jiraid.upcase }
validates :jiraid, uniqueness: true
validates :jiraid, :project, :owner, :time_forecast, :time_real, presence: true
validates :jiraid, format: { with: /\b[a-zA-Z]{2,6}-[1-9]\d{0,3}\b/, message: 'must follow this format ABCXYZ-9999' }
validates :time_real, numericality: { only_float: true }
validates :time_forecast, numericality: { only_float: true }
end
class DailyreportIssue < ApplicationRecord
belongs_to :dailyreport
belongs_to :issue
end
I use nested forms 'cocoon gem' to generate issues inside the create form of the dailyreport.
I successfully implemented that with these 2 controllers:
class DailyreportsController < ApplicationController
helper DailyreportsHelper
before_action :define_dailyreport, only: [:edit, :show, :update, :destroy]
def index
#dailyreports = Dailyreport.all.order(created_at: :desc).page params[:page]
end
def new
#dailyreport = Dailyreport.new
#dailyreport.issues.build
#issues = Issue.all.order(created_at: :desc)
end
def edit
end
def show
end
def owner_dailyreport
#owner_dailyreport = current_user.owner.dailyreports
end
def create
#dailyreport = Dailyreport.new(dailyreport_params)
#dailyreport.issues.each do |cr_issue|
call_jira_api("https://agenceinspire.atlassian.net/rest/api/3/issue/#{cr_issue.jiraid}")
if #response_output_issues.key?('errors')
flash.alert = "Please check if #{cr_issue.jiraid} exists and is available on JIRA"
no_api_reponse
else
issue_details_from_jira(cr_issue)
issue_time_real_from_jira(cr_issue)
end
if #dailyreport.save!
redirect_to #dailyreport, notice: 'Dailyreport was successfully created.'
else
render :new
end
end
end
def update
if #dailyreport.update(dailyreport_params)
redirect_to #dailyreport, notice: 'Dailyreport was successfully updated.'
else
render :edit
end
end
def destroy
if current_user.admin? || current_user.email == #dailyreport.owner.email
#dailyreport.destroy
else
admin_only_access
end
previous_page
end
private
def dailyreport_params
params.require(:dailyreport).permit(
:comment,
:owner_id,
issues_attributes: [
:jiraid,
:project_id,
:owner_id,
:time_forecast,
:time_real,
:departement,
:retour_test,
:status,
:_destroy
]
)
end
def define_dailyreport
#dailyreport = Dailyreport.find(params[:id])
end
end
class IssuesController < ApplicationController
require 'net/http'
require 'uri'
before_action :define_issue, only: [:show, :edit, :update, :destroy]
before_action :admin_only_access, only: [:destroy, :edit, :update]
def index
#issues = Issue.all.order(created_at: :desc).page params[:page]
end
def search
if params[:search].blank?
redirect_to issues_path and return
else
#parameter = params[:search].downcase
#results = Issue.all.where('lower(jiraid) LIKE :search', search: "%#{#parameter}%").page params[:page]
end
end
def new
#issue = Issue.new
end
def show
call_jira_api("https://agenceinspire.atlassian.net/rest/api/3/issue/#{#issue.jiraid}")
if #response_output_issues.key?('errors')
flash.alert = "Please check if #{#issue.jiraid} exists and is available on JIRA"
no_api_reponse
else
issue_details_from_jira(#issue)
yes_api_response
end
end
def create
#issue = Issue.new(issue_params)
# Check if issue exists on JIRA
unless call_jira_api("https://agenceinspire.atlassian.net/rest/api/3/issue/#{#issue.jiraid}")
flash.alert = "Please check if #{#issue.jiraid} exists and is available on JIRA"
end
# Get issue details from JIRA
issue_details_from_jira(#issue)
issue_time_real_from_jira(#issue)
# Save the issue
if #issue.save
flash.notice = "Issue #{#issue.jiraid} created"
redirect_to issues_path and return
else
flash.alert = "There was a problem saving #{#issue.jiraid}, check if all the fields are filled on the JIRA issue"
end
end
def edit
end
def update
if #issue.update(issue_params)
redirect_to issues_path
else
render :edit, status: :unprocessable_entity
end
end
def destroy
if current_user.admin?
#issue.destroy
else
admin_only_access
end
previous_page
end
private
def issue_params
params.require(:issue).permit(
:jiraid,
:project_id,
:owner_id,
:time_forecast,
:time_real,
:departement,
:retour_test,
:status
)
end
def define_issue
#issue = Issue.find(params[:id])
#issue_owner = Owner.find_by(params[:current_user])
end
end
My routesRails.application.routes.draw do
get '/search', to: 'issues#search'
get '/home/jira', to: 'home#jira'
get '/dailyreports/owner_dailyreport/:id', to: 'dailyreports#owner_dailyreport', :as => 'my_crs'
resources :projects
resources :issues
resources :departements
resources :owners
resources :dailyreports
# Devise routes
devise_scope :user do
get 'users', to: 'devise/sessions#new'
end
devise_for :users
authenticated :user do
root to: 'home#index', as: :authenticated_root
end
root to: redirect('/users/sign_in')
end
I am trying to implement an update or create process:
Check if the JIRAID exists in my DB
If it doesn't just get the data and save the dailyreport.
If it does, I call the API and get its updated details then update it and save the dailyreport.
And here I found some issues with the code I tried.
First when I update the issue then try to save the dailyreport, it throws the validation error (Jiraid exists) because the dailyreport.save is trying to update the issue again.
I also tried this:
def create
#dailyreport = Dailyreport.new(dailyreport_params)
issues_attributes = params[:dailyreport][:issues_attributes]
p("///////////////////////////////////ISSUES_ATTRIBUTES#{issues_attributes}")
issues_attributes.each do |_, issue_attributes|
p("~~~~~~~~~~~~~~~~~~~~~~ISSUE_ATTRIBUTE#{issue_attributes}")
# Call the JIRA API and check for errors
call_jira_api("https://agenceinspire.atlassian.net/rest/api/3/issue/#{issue_attributes["jiraid"]}")
if #response_output_issues.key?('errors')
flash.alert = "Please check if #{issue_attributes["jiraid"]} exists and is available on JIRA"
return
end
# Update the issue attributes with details from the JIRA API
issue_details_from_jira(issue_attributes)
issue_time_real_from_jira(issue_attributes)
p("~~~~~~~~~~~~~~~~~~~~~~JIRA ID IN THE DB: #{issue.jiraid}")
# Check if the issue already exists in the database
issue = Issue.find_by(jiraid: issue_attributes["jiraid"])
if issue
issue_details_from_jira(issue)
issue_time_real_from_jira(issue)
# Update the existing issue
issue.update(
time_forecast: issue.time_forecast,
time_real: issue.time_real,
status: issue.status
)
else
# Build and save a new issue if it doesn't exist
#dailyreport.issues.build(issue_attributes)
end
end
I know I have an issue here:
issue_details_from_jira(issue_attributes)
issue_time_real_from_jira(issue_attributes)
I am going to have to create an object to pass to my methods. But i don't know how.
I couldn't update the issue from the dailyreport controller too, so I tried passing the update method (+ the id) inside the strong params of the dailyreport. That resulted in a ForbiddenAttributes error.
I actually need a lead of how to approach this, not a specific solution. I think that my approach is wrong.
thank you in advance

form_for nested route url generation error

I have two models tea and a review. I have nested a route to create reviews for a specific tea but when I submit the form I am getting a UrlGeneration Eror based on missing a required key. Below is the controller action and route and picture of the error. I am trying to have a user create a new review from /teas/1/reviews/new it is a nested form the issue being it does not save the create.
Review Model
class Review < ApplicationRecord
belongs_to :user
belongs_to :tea
validates :title, presence: true
validates :rating, numericality: {only_integer: true, greater_than_or_equal_to: 0, less_than: 11}
validates :tea, uniqueness: {scope: :user, message: "has already been reviewed by you" }
scope :order_by_rating, ->{left_joins(:reviews).group(:id).order('avg(rating) desc')}
end
class ReviewsController < ApplicationController
before_action :set_review, only:[:create, :show, :edit, :update, :destroy]
def new
if #tea = Tea.find_by_id(params[:tea_id])
#review = #tea.reviews.build
else
#review = Review.new
end
end
def create
#review = current_user.reviews.build(review_params)
if #review.valid?
#review.save
redirect_to new_review_path(#review)
else
render :new
end
end
def show
#review = Review.find_by_id(params[:id])
end
def index
if #tea = Tea.find_by_id(params[:tea_id])
#reviews = #tea.reviews
else
#reviews = Review.all
end
end
def edit
end
def update
#review.update(review_params)
redirect_to tea_reviews_path(current_user.id)
end
def destroy
#review.destroy
flash[:delete_review] = "Review Deleted!"
redirect_to reviews_path(#review)
end
private
def review_params
params.require(:review).permit(:tea_id, :content, :rating,:title)
end
def set_review
#review = Review.find_by_id(params[:id])
redirect_to reviews_path if !#review
end
end
Route
resources :reviews
resources :teas do
resources :reviews, only: [:new, :index]
end
In line 62 of Reviews_controller
redirect_to review_path if !#review
In this line you are trying to redirect to a review show page if review doesn't exist,
hence when review doesn't exist it redirects to show path without an id, that's why you are getting an error.
Think carefully where do you want to redirect, if a review does not exist.
Per your updated question,
Remove :create from the before_action in the first line of the controller,
also, in your create action change the redirect to
redirect_to reviews_path
after the #review.save.

"undefined method `slug'" when trying to save nested route using Friendly_id 5

My App allows a user to create an Event and people can RSVP to the event. The app worked well before adding the Friendly_id gem, it works well as far as creating a new Event, but the RSVPs do not work as when you click submit you get an error. Please look at my code and see if there is anything that I am missing. Thank you in advance.
Event Model
class Event < ApplicationRecord
extend FriendlyId
friendly_id :eventname, use: [:slugged, :finders]
belongs_to :user
def should_generate_new_friendly_id?
eventname_changed?
end
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/placeholder.png"
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
validates :eventname, presence: true
has_many :rsvps, dependent: :destroy
end'
Rsvp Model
class Rsvp < ApplicationRecord
extend FriendlyId
friendly_id :eventname, use: [:slugged, :finders]
belongs_to :event
end
Events Controller
class EventsController < ApplicationController
before_filter :authenticate_user!, except: [:show]
def index
#events = current_user.events.all
end
def show
#event = Event.friendly.find(params[:id])
end
def new
#event = current_user.events.build
end
def create
#event = current_user.events.build(event_params)
#event.user = current_user
respond_to do |format|
if #event.save
format.html { redirect_to #event, notice: "Successfully created" }
else
format.html { render "new" }
end
end
end
def edit
#event = Event.friendly.find(params[:id])
end
def update
#event = Event.friendly.find(params[:id])
if #event.update(event_params)
redirect_to #event
else
render 'edit'
end
end
def destroy
#event = Event.friendly.find(params[:id])
#event.destroy
redirect_to events_path
end
private
def event_params
params.require(:event).permit(:eventname, :date, :time, :venue, :description, :image)
end
end
Rsvp Controller
class RsvpsController < ApplicationController
def index
event = Event.friendly.find(params[:event_id])
#rsvps = event.rsvps
end
def new
event = Event.friendly.find(params[:event_id])
#rsvp = event.rsvps.friendly.build
respond_to do |format|
format.html
end
end
def create
event = Event.friendly.find(params[:event_id])
#rsvp = event.rsvps.build(rsvp_params)
respond_to do |format|
if #rsvp.save
format.html { redirect_to "/thanks" }
format.js
else
format.html { render :new }
format.js
end
end
end
def thanks
render params[:page]
end
private
def rsvp_params
params.require(:rsvp).permit(:status, :name, :message)
end
end
Routes
resources :events do
resources :rsvps
end
show event:
http://127.0.0.1:3000/events/birthday
create rsvp for event:
http://127.0.0.1:3000/events/3/rsvps/new
After submit error shows on:
http://127.0.0.1:3000/events/birthday/rsvps
Screenshot of Error I get
I managed to resolve this issue by updating the following:
class Rsvp < ApplicationRecord
belongs_to :event
end
changed this:
new_event_rsvp_path(event_id: #event.id)
to this:
new_event_rsvp_path(#event)
Creating new RSVP now shows in the Friendly_id way:
http://127.0.0.1:3000/events/birthday/rsvps/new

updating resource undefined method `valid?' for false:FalseClass

I have some validations for my Lesson model, and I'm able to highlight validation problems on the controller under the create action with the valid? method. However, if I try to valid? in an analogous manner, I get undefined methodvalid?' for false:FalseClass` How can I go about validating my edit form upon submission, such that it renders the edit form again if the validation doesn't pass?
Lesson model:
class Lesson < ActiveRecord::Base
belongs_to :user
has_many :words, dependent: :destroy
validates :title, presence: true, length: { maximum: 55 }
validates :description, presence: true, length: { maximum: 500 }
validates :subject, presence: true, length: { maximum: 55 }
validates :difficulty, presence: true, numericality: { less_than_or_equal_to: 5 }
end
Controller:
class Teacher::LessonsController < ApplicationController
before_action :authenticate_user!
before_action :require_authorized_for_current_lesson, only: [:show, :edit, :update]
def show
#lesson = Lesson.find(params[:id])
end
def new
#lesson = Lesson.new
end
def edit
#lesson = Lesson.find(params[:id])
end
def create
#lesson = current_user.lessons.create(lesson_params)
if #lesson.valid?
redirect_to teacher_lesson_path(#lesson)
else
render :new, status: :unprocessable_entity
end
end
def update
#lesson = current_lesson.update_attributes(lesson_params)
if #lesson.valid?
redirect_to teacher_lesson_path(current_lesson)
else
render :edit, status: :unprocessable_entity
end
end
private
def require_authorized_for_current_lesson
if current_lesson.user != current_user
render text: "Unauthorized", status: :unauthorized
end
end
def current_lesson
#current_lesson ||= Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :description, :subject, :difficulty)
end
end
If you see an error that looks like undefined method 'valid?' for 'false:FalseClass
That means that wherever you call the method :valid?, the object on which you are calling it is not the object you expect, it is instead just false
So you have two instances in your code where you are calling #lesson.valid?, which means one or both of the assignments of #lesson is sometimes returning false.
In the docs of create, it says: The resulting object is returned whether the object was saved successfully to the database or not.
In the docs of update_attributes, it says: If the object is invalid, the saving will fail and false will be returned.
So it looks like your problem is with update_attributes, which apparently just returns false if your update was unsuccessful.

Rails: am I nesting incorrectly?

Hi I'm currently working on my first project, and am trying to build the functionality first before doing the login/sessions. I'm trying to create a picture album website, where users have many albums (that contain many pictures), and album access is shared among friends. However, I'm noticing that after my albums#create
http://localhost:3000/users/18/albums/new (no problem here)
I am redirected to albums#show:
http://localhost:3000/albums/20 (problem!!)
shouldn't there be a user_id in the URL as well?? Or does it not have a user_id attached to the URL because it belongs to multiple users? Here are my routes:
Pholder::Application.routes.draw do
resources :users do
resources :albums
end
resources :albums do
resources :pictures
end
root :to => "users#index"
Here are my models in case:
user model
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :name, :password, :password_confirmation
validates_presence_of :password, :on => :create
validates_format_of :name, :with => /[A-Za-z]+/, :on => :create
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
validates_length_of :password, :minimum => 5, :on => :create
has_many :user_albums
has_many :albums, :through => :user_albums
accepts_nested_attributes_for :albums
end
album model
class Album < ActiveRecord::Base
attr_accessible :avatar, :name, :description
has_many :user_albums
has_many :users, :through => :user_albums
has_many :photos
end
photo album
class Photo < ActiveRecord::Base
belongs_to :album
end
albums controller
class AlbumsController < ApplicationController
def index
#albums = Albums.all
respond_to do |format|
format.html
format.json { render json: #albums }
end
end
def show
#albums = Album.all
#album = Album.find(params[:id])
#photo = Photo.new
end
def update
end
def edit
end
def create
# #user = User.find(params[:albums][:user_id])
# #users = User.all
#album = Album.new(params[:album])
# #album.user_id = #user.id
respond_to do |format|
if #album.save
format.html { redirect_to #album, notice: 'Album was successfully created.' }
format.json { render json: #album, status: :created, location: #album}
else
format.html { render action: "new" }
format.json { render json: #album.errors, status: :unprocessable_entity }
end
end
end
def new
#user = User.find(params[:user_id])
#album = Album.new
end
def destroy
end
end
Let me know if you need any other files.
The line redirect_to #album makes you redirect to the show action of the #album in question.
Changing this piece of code to something like redirect_to users_path will make the app redirect to the index action of users_controller and so on.
It depends on whatever behavior you want after the save.
Reading this should be helpful too: http://guides.rubyonrails.org/routing.html

Resources