Undefined constant Rails 4 - ruby-on-rails

by copying and trying to modify a scaffold manually in Rails 4, I got an error when I want to delete an article: uninitialized constant Article::Tag.
Another error when I want to edit an Article: "undefined local variable or method `article_params'".
I don't know from where it can comes from, the highlited error which are displayed are #article.destroy and if #article.update(article_params). I don't understand at all considering I think having copied perfectely the scaffold...
def destroy
#article.destroy
respond_to do |format|
format.html { redirect_to articles_url }
format.json { head :no_content }
end
end
def update
respond_to do |format|
if #article.update(article_params)
format.html { redirect_to #article, notice: 'Article was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #article.errors, status: :unprocessable_entity }
end
end
end
Thansk you for your help

Related

Unknown reason why I'm getting a: undefined method `map' for nil:NilClass error

I'm getting an undefined method `map' for nil:NilClass when I attempt to save my forum.
Here is my jobs_controller.rb:
def new
#job_categories = JobCategory.all.map{|c| [ c.title, c.id ] }
#job = Job.new
end
def edit
#job_categories = JobCategory.all.map{|c| [ c.title, c.id ] }
#job = Job.find(params[:id])
end
def create
#job = Job.new(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: #job }
else
format.html { render :new }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully
updated.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :edit }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
Here is my jobs/_form.html.erb:
<div class="field-group">
<p>Jobs Category</p>
<%= form.select(:job_category_id, options_for_select(#job_categories)) %>
My jobs_categories has it's own controller and model also.
If you need any other information feel free to ask.
My error is happening when I try to submit my form.
#job_categories variable is missing form create and update actions. It causes errors when form renders after an unsuccesfull save - options_for_select tries to call .map on undeclared variable.

Rails/RoR - NoMethodError (undefined method `destroy' for nil:NilClass)

I have a TranslationsUser table and a FavoriteTranslation table. I want a TranslationsUser to only have one favorite translation, however I do not want to use validations because I want my controller to replace a favorite translation if one already exists. Instead, I created a validate_uniqueness function.
When I try to replace a TranslationsUser with a new favorite translation, I get the following error in my terminal:
NoMethodError (undefined method `destroy' for nil:NilClass):
I think the problem may be the before action :set_favorite_translation since it defines #favorite_translation
If so, how can I delete a specific FavoriteTranslation record: transUser.favorite_translations.first
If not, please help me figure out what the issue is! Many thanks.
before_action :set_favorite_translation, only: [:show, :edit, :update, :destroy]
def create
transUser = TranslationsUser.find(favorite_translation_params[:translations_user_id])
#favorite_translation = FavoriteTranslation.new(favorite_translation_params)
#favorite_translation.user_id = #current_user.id
if validate_uniqueness(transUser) == false
transUser.favorite_translations.first.destroy
end
respond_to do |format|
if #favorite_translation.save
#format.html { redirect_to #favorite_translation, notice: 'Translations users comment was successfully created.' }
format.json { head :no_content }
else
format.html { render :new }
format.json { render json: #favorite_translation.errors, status: :unprocessable_entity }
end
end
end
def validate_uniqueness(transUser)
if FavoriteTranslation.joins(:translations_user).where('lang_id = ?', transUser.lang_id).where('favorite_translations.user_id = ?', #current_user.id).where('translations_users.translation_id = ?', transUser.translation_id).exists?
return false
else
return true
end
end
def destroy
#favorite_translation.destroy
respond_to do |format|
format.html { redirect_to favorite_translations_url, notice: 'Translation was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_favorite_translation
#favorite_translation = FavoriteTranslation.find(params[:id])
end
I guess you are almost there. Just add the following inside the destroy method.
def destroy
if #favorite_translation
#favorite_translation.destroy
end
respond_to do |format|
format.html { redirect_to favorite_translations_url, notice: 'Translation was successfully destroyed.' }
format.json { head :no_content }
end
end
This basically checks if the favorite_translation is present, else the translationUser don't have a favorite_translation and so will allow the new record to be created.
If you don't want validations, no worries, writing proper associations will help you and DRY up your code as well.
Firstly, use has_one :favorite_translation and belongs_to :translations_user associations, then in you create action..
def create
transUser = TranslationsUser.find(favorite_translation_params[:translations_user_id])
#favTrans = transUser.favorite_translation || transUser.build_favorite_translation
#favTrans.assign_attributes(favorite_translation_params)
respond_to do |format|
if #favTrans.save
format.html { redirect_to #favTrans, notice: 'Translations users comment was successfully created.' }
format.json { head :no_content }
else
format.html { render :new }
format.json { render json: #favTrans.errors, status: :unprocessable_entity }
end
end
end
Now you don't need to destroy records and use has_many relations, create and update are kinda merged here.
I tried the given solutions, but I found that the following worked. Thanks for all the help!!!!
def create
transUser = TranslationsUser.find(favorite_translation_params[:translations_user_id])
if validate_uniqueness(transUser) == true
#favorite_translation = FavoriteTranslation.new(favorite_translation_params)
#favorite_translation.user_id = #current_user.id
else
update
end
respond_to do |format|
if #favorite_translation.save
format.json { head :no_content }
else
format.html { render :new }
format.json { render json: #favTrans.errors, status: :unprocessable_entity }
end
end
end
def update
transUser = TranslationsUser.find(favorite_translation_params[:translations_user_id])
#favorite_translation = FavoriteTranslation.joins(:translations_user).where('lang_id = ?', transUser.lang_id).where('favorite_translations.user_id = ?', #current_user.id).where('translations_users.translation_id = ?', transUser.translation_id).first
#favorite_translation.translations_user_id = favorite_translation_params[:translations_user_id]
#favorite_translation.save
respond_to do |format|
if #favorite_translation.update(favorite_translation_params)
'Translations users comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render :edit }
format.json { render json: #favorite_translation.errors, status: :unprocessable_entity }
end
end
end
I removed this line
config.action_view.javascript_expansions[:defaults] = %w(jquery.min jquery_ujs)
from application.rb to resolve the issue.

Rails: How to update multiple models together, with proper rollback (kind of manual nested attributes)

I (for various reasons) have decided not to use nested_attributes. Here is my current controller:
def update
# Update snippet
#snippet.update(snippet_params)
# Update hotspot
#snippet.hotspot.update(hotspot_params)
# Update text
#snippet.text.update(medium_params_with(:text))
# Update audio
if params[:audio] {
#snippet.audio.destroy
#snippet.media << Audio.new(medium_params_with(:audio))
}
respond_to do |format|
if success = true #fix this up
format.html { redirect_to #project, notice: 'Snippet was successfully updated.' }
format.json { render :show, status: :ok, location: #snippet }
else
format.html { redirect_to #project, warning: 'Highlight was not updated.' }
format.json { render json: #snippet.errors, status: :unprocessable_entity }
end
end
end
This is more or less OK if nothing goes wrong.
How do I wrap this into something like:
try {
update everything
} else {
undo any changes I made while trying to update everything
}
if success {
etc
} else {
etc
}
If what you are changing are ActiveRecord models using a SQL database then http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html might provide exactly what you're looking for.
Following #Jonah's answer, I wrapped the DB changes in ActiveRecord::Base.transaction:
def update
success = ActiveRecord::Base.transaction do
# Update snippet
#snippet.update(snippet_params)
# Update text
#snippet.text.update(medium_params_with(:text))
# Update audio
if params[:audio]
#snippet.audio.destroy
#snippet.media << Audio.new(medium_params_with(:audio))
end
end
respond_to do |format|
if success
format.html { redirect_to #project, notice: 'Snippet was successfully updated.' }
format.json { render :show, status: :ok, location: #snippet }
else
format.html { redirect_to #project, warning: 'Highlight was not updated.' }
format.json { render json: #snippet.errors, status: :unprocessable_entity }
end
end
end

too few arguments with scaffold code

The join method below in the teams_controller.rb is sent the following data through submission of a form using EmberJs
{"id"=>"3", "user_id"=>"42", "action"=>"join", "controller"=>"teams"}
The record is getting created with the join method below (according to the console), but the code for what happens after the save is throwing an error
ArgumentError (too few arguments):
app/controllers/teams_controller.rb:145:in `format'
app/controllers/teams_controller.rb:145:in `join'
I copied the code following the #team.save method from the Rails scaffold generator, so I'm a little surprised. The hope is that it will respond with the json, but I left in the html format just because (maybe there's a graceful degradation benefit). Can you tell me why that error's being thrown and/or how I could avoid it?
Rails method
def join
#team = Team.find(params[:id])
id = params[:user_id]
#team.user_ids = #team.user_ids.push(id)
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
Update,
I should also note that, based on the line number of the error message, the method seems to be treating the format as html, however, I wanted it to be treated as json
I forgot to put respond_to do |format| around the code.
respond_to do |format|
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end

How to display an error message on a destroy action, since it redirects to index action?

In a model I have:
before_destroy :ensure_not_referenced_by_any_shopping_cart_item
and
def ensure_not_referenced_by_any_shopping_cart_item
unless shopping_cart_items.empty?
errors.add(:base, "This item can't be deleted because it is present in a shopping cart")
false
end
end
When the item is present in a cart, it is not destroyed (which is good), and I see the error if I log it in the action..
def destroy
#product = Beverage.find(params[:id])
#product.destroy
logger.debug "--- error: #{#product.errors.inspect}"
respond_to do |format|
format.html { redirect_to beverages_url }
format.json { head :ok }
end
end
..but the instance variable on which the error message was set is abandoned when the redirect_to happens, so the user never sees it.
How should the error message be persisted to the next action so it can be shown in its view?
Thanks!
I would recommend using a flash message to relay the error information.
respond_to do |format|
format.html { redirect_to beverages_url, :alert => "An Error Occurred! #{#products.errors[:base].to_s}"
format.json { head :ok }
end
Something to that effect. That is how I have handled similar issues in my own apps, but it depends on the detail of information you want to display to the user.
You need to put the error in the flash. Something roughly like
def destroy
#product = Beverage.find(params[:id])
if #product.destroy
message = "Product destroyed successfully"
else
message = "Product could not be destroyed"
end
respond_to do |format|
format.html { redirect_to beverages_url, :notice => message }
format.json { head :ok }
end
end
Note that you also need to be printing out messages in your application.html.erb file.
You can do it with two messages, one with the status OK, and another with NO OK (unprocessable_entity for example, here's more).
def destroy
#product = Beverage.find(params[:id])
respond_to do |format|
if #product.destroy
format.html { redirect_to beverages_url, notice: "Product destroyed successfully", status: :ok}
format.json { head :ok, status: :ok}
else
format.html { redirect_to beverages_url, alert: "Product could not be destroyed", status: :unprocessable_entity}
format.json {head :no_content, status: :unprocessable_entity }
end
end
end
In Rails 4, you can do like that
def destroy
#product = Beverage.find(params[:id])
respond_to do |format|
if #product.destroy
format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
format.json { head :ok }
else
format.html { render :show }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end

Resources