I have a new select box appearing after edit. The model that I modified in the edit is another model using fields_for option.
Someone mentioned that I had the problem with the new and create actions in the controller.
the current controller:
def new
#print = Print.new
end
def create
#print = Print.new(params[:print])
#print.user_id = current_user.id
if #print.save
redirect_to print_path(#print), :flash => { :success => "Successfully created your Print Order." }
else
render :action => 'new'
end
end
def edit
#print = Print.find(params[:id])
#print.blackwhites.build
end
The fields_for that edit data from the model:
def index
def new
#blackwhite = Blackwhite.new
end
def create
#blackwhite = Blackwhite.new(params[:blackwhite])
#blackwhite.print_id = #print.id
end
def update
#blackwhite = Blackwhite.find(params[:id])
end
def show
#blackwhite = Blackwhite.find(params[:id])
end
def edit
#blackwhite = Blackwhite.find(params[:id])
end
Edit:
Fixed the problem.
The first thing I see:
def create
#blackwhite = Blackwhite.new(params[:blackwhite])
#blackwhite.print_id = #print.id
render :action => 'new' <<<< ?????
end
Try
redirect_to print_path(#print)
That would be the typical default thing to do, show the data that just got created, or in your nested case, show the parent of the record that just got created. All you really need to do is STOP rendering the new action after you create, that's NOT right!
Related
When a post is updated I want to grab the number of words before it is saved and subtract that from the newly saved post word count. I want to do this in the post update controller.
Here is the update method
def update
#guide = Guide.friendly.find(params[:guide_id])
#post = Post.friendly.find(params[:id])
post_word_count_before = #no idea how to get it
post_word_count_after = #post.post.scan(/\w+/).size
change_in_words = post_word_count_after - post_word_count_before
if #post.update post_params
PostContributer.create!(user_id: current_user.id, post_id: #post.id, no_of_contributions: 1, no_of_words_contributed: change_in_words)
redirect_to guide_post_path(#guide, #post)
flash[:success] = "Updated successfully"
else
render 'edit'
end
end
I'm using #post.post.scan(/\w+/).size to get the word count after the post is updated. But I dont know how to get the word count before it is updated and store it in the variable post_word_count_before
The #post object is not changed until the #post.update post_params line, so the way you have it, the post_word_count_after variable contains the word count before the update.
I think this is what you are after:
def update
#guide = Guide.friendly.find(params[:guide_id])
#post = Post.friendly.find(params[:id])
post_word_count_before = #post.post.scan(/\w+/).size
if #post.update post_params
post_word_count_after = #post.post.scan(/\w+/).size
change_in_words = post_word_count_after - post_word_count_before
PostContributer.create!(user_id: current_user.id, post_id: #post.id, no_of_contributions: 1, no_of_words_contributed: change_in_words)
redirect_to guide_post_path(#guide, #post)
flash[:success] = "Updated successfully"
else
render 'edit'
end
end
active_model which is mixed into active_record provides API for record changes. You could use record.changes which provides hash of all the attributes that got changed with before and after values.
So instead of putting all that business logic in the controller, I would that rather move that into model where it belongs and with the use of ActiveModel::Dirty API and the callbacks you could achieve what you are after.
For example: Following could be your updated controller logic, clean and simple
class PostsController < ApplicationController
before_action :load_guide, only [:update] # add other actions that require #guide
before_action :load_post, only [:update] # add other actions that require #guide
def update
if #post.update(post_params)
redirect_to(guide_post_path(#guide, #post), success: "Updated successfully")
else
render 'edit'
end
end
private
def load_guide
#guide = Guide.friendly.find(params[:guide_id])
end
def load_post
#post = Post.friendly.find(params[:id])
#post.contributer = current_user
end
end
And your updated model:
class Post < ActiveRecord::Base
attribute_accessor :contributer # to get the current_user info from controller
before_update :create_post_contributer!
def create_post_contributer!
before = self.changes[:post][0].scan(/\w+/).size
after = self.changes[:post][1].scan(/\w+/).size
change_in_words = after - before
PostContributer.create!(
user_id: self.contributer.id,
post_id: self.id,
no_of_contributions: 1,
no_of_words_contributed: change_in_words
)
end
end
Refer to ActiveModel::Dirty for more info.
Try using it through session.
Store the previous updated value in session variable and delete the session variable once you do all the calculation from older post and newer post.
Im using a gem called MetaInspector to scrape data from different websites. Im building a site where i can collect data from different sites but am having trouble setting up. I have a model called site with a title and a url both strings. When i create a new "site" the name will come out as example.com/"sitename" and in there i would like to have the data just from that site. I kinda have an idea to this by adding page = MetaInspector.new to the new method but cant see how i can set a url in there.
I can show my controller and other info if needed.
Controller
class Admin::SitesController < Admin::ApplicationController
def index
#sites = Site.all
end
def show
#site = Site.friendly.find(params[:id])
end
def edit
#site = Site.friendly.find(params[:id])
end
def update
#site = Site.friendly.find(params[:id])
if #site.update(site_params)
redirect_to admin_path
else
render :edit
end
end
def destroy
#site = Site.friendly.find(params[:id])
#site.destroy
if #site.destroy
redirect_to admin_path
end
end
def new
#site = Site.new
end
def create
#site = Site.new(site_params)
if #site.save
redirect_to admin_path
else
render :new
end
end
private
def site_params
params.require(:site).permit(:title, :url)
end
end
If I understand correct you want to show the metainfo for a Site you have added. You could put that code in the show action of the controller:
def show
#site = Site.friendly.find(params[:id])
#page = MetaInspector.new(#site.url)
end
And update the show.html.erb template to display info about #page, ie:
<%= #page.title %>
In the code below, I am trying to set the popup variable for the Company object, but where it currently is located, it is not getting set when the user hits the submit button on the page where a company object is created.
When I put the line in question before the if statement, the popup variable gets set, but because the object hasn't been saved yet, the #company.id has been set yet, so that part of the popup string I am trying to create isn't set properly.
Any ideas how to get my popup variable to be set properly?
def create
#company = Company.new(company_params)
if #company.save
redirect_to map_path
flash[:success] = "Company Successfully Added"
#company.popup = "<h3><a href='companies/#{#company.id}'>#{#company.name}</a></h3>"
else
render 'new'
end
end
If popup is a company attribute and if you need to save it, just use 'before_save':
def create
#company = Company.new(company_params)
if #company.save
redirect_to map_path
flash[:success] = "Company Successfully Added"
else
render 'new'
end
end
Model:
before_save :set_popup_value
private
def set_popup_value
popup = "<h3><a href='companies/#{self.id}'>#{self.name}</a></h3>"
#self.update_attributes(:popup => popup)
self.update_column(:popup => popup)
end
else, if you want 'popup' just to display it and not to save in a database, then you must use attr_accessor.
Model:
class Company < ActiveRecord::Base
attr_accessor :popup
end
Controller:
def create
#company = Company.new(company_params)
if #company.save
#company.popup = "<h3><a href='companies/#{#company.id}'>#{#company.name}</a></h3>"
redirect_to map_path
flash[:success] = "Company Successfully Added"
else
render 'new'
end
end
Hope it helps :)
In my create action, method new acts like create.
def create
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
if #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
ActiveRecord creates new object in database while I'm using new with params. Page.new works fine in new action in my controller. What can be the reason? There is no overridden method new and no callbacks (before_save, before_create etc) in my model. Any help would be appreciated.
UPDATE - code from debugger
.../app/controllers/pages_controller.rb:48
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
(rdb:25) #page
nil
(rdb:25) n
.../app/controllers/pages_controller.rb:49
if #page.save
(rdb:25) #page
#<Page id: 80 ... >
(rdb:25) Page.last
#<Page id: 80 ... >
(rdb:25) #page.save
false
Check my inline comments..
def create
#page = Page.new(params[:page].merge(:user_id => current_user.id )) # you trigger new thats fine..
if #page.save # Notice here.. This line is triggering query on database.
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
Reason (method in model which can change status in workflow):
def status=(state_name)
states = [self.current_state.to_sym]
possible_states.each {|t| states<< t[1]}
unless state_name.blank?
if states.include? state_name
process_event! state_name
end
end
end
Ugly fix
def create
#page = Page.new
if #page.update_attributes(params[:page].merge(:user_id => current_user.id )) && #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
Mistake was quite silly and I'm not proud of my solution. Anyway, thanks for help:)
With an ActiveRecord class, create = new + save
https://github.com/rails/rails/blob/7edade337e968fb028b2b6abfa579120eb424039/activerecord/lib/active_record/persistence.rb#L40
Your controller code is correct. This is how a 'create' controller method should work. The problem is not there.
Are you certain you're having two models created?
The .new method you're calling with the attributes creates an activerecord object in memory that's unsaved. The .save method saves it. At the end (assuming the data is valid) you should have a single object in memory.
If you have two objects created, then there is a problem. If you have only one, then it's as it should be.
Are you having a second object created by this controller method?
The process should be:
# when GET /student/new is called, this returns an empty object to display in the form
# for the user to see.
def new
#page = Page.new
end
# When POST /page is called, the form params are passed in here.
def create
# First, generate a new page object with the params passed in.
#page = Page.new(params[:page].merge(:user_id => current_user.id ))
# Now try save the object to persist it in the database.
if #page.save
flash[:notice] = t("success")
redirect_to pages_path
else
render :new
end
end
I have a model called Details that contains a method that updates some attributes with calculations by using another model's (Summary) attributes. I call that method into a before_saveto make Details' attributes update automatically when I modify an entry. I would like to make my Details' attributs update when I modify my entries in the Summary model. What I'm searching is something that could be used like that :
def update
#summary = Summary.find(params[:id])
if #summary.update_attributes(params[:summary])
(Details.update_all_attributes)
flash[:notice] = "Updated!"
redirect_to edit_summary_path(#summary)
else
render :action => 'edit'
end
end
See the line : Details.update_all_attributes. All my Details' attributs would be saved and recalculated because of the before_save I have put. How can I do that ? Thanks.
Edit :
I just found the answer. I did a loop that saves all my entries.
def update
#summary = Summary.find(params[:id])
if #summary.update_attributes(params[:summary])
#details = Details.all
#details.each do |detail|
detail.save!
end
flash[:notice] = "Updated!"
redirect_to edit_summary_path(#summary)
else
render :action => 'edit'
end
end
Hope I will help some of you !
Fat models, skinny controllers:
Model
class Summary < ActiveRecord::Base
after_update :recalculate_details
private
def recalculate_details
Detail.all.each {|d| d.save! }
end
end
Controller
def update
#summary = Summary.find(params[:id])
if #summary.update_attributes(params[:summary])
flash[:notice] = "Updated!"
redirect_to edit_summary_path(#summary)
else
render :action => 'edit'
end
end