I'm new to Rails, and am trying to make a pet app. It has 3 attributes: name, hungry, and mood. I generated a scaffold and wrote a feed method into the model:
def feed
self.hungry==false;
save!
end
I want feed to be something a user can do in the edit view, so I created a checkbox to indicate feeding vs. not feeding. My plan was to call the feed function from the controller in the update function. Right now, it looks like this:
def update
respond_to do |format|
if #pet.update(pet_params)
format.html { redirect_to #pet, notice: 'Pet was successfully updated. #{params[:feed]}' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #pet.errors, status: :unprocessable_entity }
end
end
if #pet.update_attributes(params[:feed])
#pet.feed
end
end
I have an odd sense that I'm mixing metaphors here, but am not sure of the right course of action. I'm trying to call a function from my update function, and that doesn't seem to be working. It might have to do with the fact that "feed" isn't listed in my model's parameters, but I don't need it to be. I just need it to call a function. Help!
Your method definition is wrong. Instead of assigning a value, you are comparing equality.
def feed
self.hungry == false; # only one = should be used.
save!
end
There is a better way to do this, however:
class Pet
attr_accessor :feed_me
before_save :feed
def feed
hungry = false if feed_me
end
end
You should not need the controller check:
if #pet.update_attributes(params[:feed])
#pet.feed
end
Which is wrong, by the way. You need to check if the param[:feed] exists, not if the pet objet has updated correctly.
For this solution to work, you would need to add an attribute to your form:
= f.check_box :feed_me
Another way to do this would be to map the hungry attribute to the checkbox and just name the label feed:
= f.label :hungry, "Feed"
= f.checkbox :hungry
You could then go ahead and just remove the before_save, the attr_accessor, and the method self.feed.
Related
I have a new and create method:
def new
#post = Post.new
puts #post
puts #post.object_id
end
def create
#post = Post.new(post_params)
puts #post
puts #post.object_id
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
For a while I thought that the create method had some rails magic tied to it where it knew how to get the instance of a model from the new method and then create it in the DB.
Realizing that this is incorrect, then, is the reason we call Post.new in the new method so that we have access to the form helpers for the object and its attributes and can pass those into Create as parameters?
Then in create... We call Post.new(params)... To me in the code it doesn't look like we explicitly call .create or .save anywhere (yes I see we check for a condition that yields true or false using save). So how does creating a new instance of an object and passing it parameters save it?
I am a little lost and am looking for some clarification, confirmation, general assistance on these beginner questions.
Or maybe I should stick with golf.
is the reason we call Post.new in the new method so that we have access to the form helpers
Yes, essentially. It allows you to use, for example, form_for #post.
To me in the code it doesn't look like we explicitly call .create or .save anywhere (yes I see we check for a condition that yields true or false using save)
Using if #post.save is calling #post.save. That saves the post, and returns true on success and false on failure. Methods can do things and also return values, and this method persist the record and returns a boolean.
When you run this line
#post = Post.new(post_params)
You are creating a new instance of Post with the parameters that are allowed, post_params is a method that is defined in the controller that permits certain attributes.
def post_params
params.require(:post).permit(:title, :content)
end
In this case, only title and content are permitted to be created with the post. The post will most likely also have a created_at, and updated_at attributes, but that is automatically set, so it is not an attribute that the user can edit/create. You can read more about strong parameters
The if statement reads
if #post.save
This is basically saying if the post can be saved without error, save the post and run the code in the if statement.
Think of it as saying if the post was successfully saved, then do this.
There are few thing to consider...
we are in RESTful environment.
Why we use Model.new
its mainly to get(GET REQUEST) the empty model to provide for the user to fill in the information.So here comes the form helpers which is used to fill in the details in the form and fill the empty bucket for the model which is the attributes and the values provided by the users using the form.
So basically ,you are only providing an emtpy record...that can be used for the user to fill in.
Why do we again user Model.new(params)
So,in continuity with above explanation,once the bucket is ready from the user,we use the create action in the form to post the data (POST REQUEST)
.So that data,if you see your sever logs in wrapped in an parent node...like
Processing by PicturesController#create as HTML
Parameters: {"picture"=>{"title"=>["testing"]}
picture model
this data is wrapped in params which you define at the controller level since Rails 4,which is as easy a using it directly like Model.new(params) which is nothing but Model.new(title: "testing") which is use to create a new object-needed for validation/callbacks to check whether user has provided valid details.
Hence,you check this with if/else statement which most rails create action has.
..HOPE IT HELPS
I'm working with validations in rails, stuff like:
validates_presence_of :some_field
I've noticed that if the validation fails, all changes are overwritten with existing values from the database. This makes some sense, as the page is basically being reloaded (as I gather from my development log), however this increases the risk of user error/frustration, as a single error in one field will require the hapless fellow to re-enter the changes he made to all fields.
My question: How can I get rails to reload the data that was just submitted if validation fails? That way, the user can correct the mistake without needing to re-enter the rest of his revisions.
Thanks for any advice.
Edit:
My update method, as requested, is as follows:
def update
#incorporation = Incorporation.find(params[:id])
#company = #incorporation.company
begin
#company.name="#{params[:company][:names_attributes].values.first["name_string"]} #{params[:company][:names_attributes].values.first["suffix"]}"
rescue NoMethodError
#company.name="Company #{#company.id} (Untitled)"
end
if #company.update(company_params)
redirect_to incorporations_index_path
else
redirect_to edit_incorporation_path(#incorporation)
end
end
Full disclosure regarding my controller: the above update is from my incorporations_controller even though I'm updating my Company model. Company has_one :incorporation. I did this because, in the larger context of my app, it made my associations much cleaner.
Update your controller to this
def update
#incorporation = Incorporation.find(params[:id])
#company = #incorporation.company
begin
#company.name="#{params[:company][:names_attributes].values.first["name_string"]} #{params[:company][:names_attributes].values.first["suffix"]}"
rescue NoMethodError
#company.name="Company #{#company.id} (Untitled)"
end
respond_to do |format|
if #company.update(company_params)
format.html { redirect_to({:action => "index"})}
else
format.html{render :edit}
format.json { render json: #incorporation.errors, status: :unprocessable_entity }
end
end
end
To add to the correct answer, you can clean up your code quite a bit:
def update
#incorporation = Incorporation.find params[:id]
respond_to do |format|
if #incorporation.update company_params
format.html { redirect_to({:action => "index"})}
else
format.html { render :edit }
format.json { render json: #incorporation.errors, status: :unprocessable_entity }
end
end
end
If you're using accepts_nested_attributes_for, you definitely should not hack the associated objects on the front-end.
You should look up fat model, skinny controller (let the model do the work):
#app/models/company.rb
class Company < ActiveRecord::Base
before_update :set_name
attr_accessor :name_string, :name_suffix
private
def set_name
if name_string && name_suffix
self[:name] = "#{name_string} #{name_suffix}"
else
self[:name] = "Company #{id} (Untitled)"
end
end
end
This will allow you to populate the name of the `company. To edit your nested/associated objects directly is an antipattern; a hack which will later come back to haunt you.
The key from the answer is: render :edit
Rendering the edit view means that your current #company / #incorporation data is maintained.
Redirecting will invoke a new instance of the controller, overriding the #incorporation, hence what you see on your front-end.
I would like the first two user inputed integer inputs of a rails app to populate a third field after some arithmetic is performed on them when a submit button is pressed.
I've used rails scaffolding.
Do I put my desired arithmetic function that I want to perform on my variables in my controller code below?
# POST /pls
# POST /pls.json
def create
#pl = Pl.new(pl_params)
respond_to do |format|
if #pl.save
format.html { redirect_to #pl, notice: 'Pl was successfully created.' }
format.json { render :show, status: :created, location: #pl }
else
format.html { render :new }
format.json { render json: #pl.errors, status: :unprocessable_entity }
end
end
end
Your question is not clear. But for this portion,the answer is,
Do I put my desired arithmetic function that I want to perform on my variables in my controller code below?
The best practice is to use model method to perform the arithmetic calculation. You can also use private controller method for this reason and call that method where you need. But its not a good practice to push the arithmetic code inside the create action.
That's something I'd actually put inside of your Pl model, in a before_save callback, so that if any of your two user inputed values changes, the value of the third is updated. It'd look something like this:
class Pl < ActiveRecord::Base
before_save :update_third_value
def update_third_value
if first_value_changed? || second_value_changed?
third_value = first_value / second_value # here is your desired arithmetic
end
end
end
Check out ActiveModel::Dirty, which is available to all models by default, and ActiveRecord::Callbacks, there's a list of all default callbacks available.
I am building a Rails app. And in my app, there are Projects where users can "Follow". When a user follows one of the pages, he/she will get updates if somebody uploads/creates a folder/file.
Below is the screenshot when somebody just created a new folder:
And below is the code for "Create" action in my Folder controller:
def create
#folder = current_user.folders.where(project_id: params[:project_id]).create(folder_params)
respond_to do |format|
if #folder.save
#folder.create_activity :create, owner: current_user, :params => {
:project_id => proc {|controller, project| #folder.project.id},
:project_name => proc {|controller, project| #folder.project.name},
}
format.html { redirect_to #folder.project, notice: 'Folder was successfully created.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { render :new }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
As you can see :project_id and :project_name are the parameters for the public_activity when a new folder being created.
And below is the screenshot on how this parameters value looks like in the database after they were saved:
QUESTION:
So my question is, how do i use this parameters values in my activities_controller?
Here is the code for my activities controller right now:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc").where(owner_id: current_user.following_users, owner_type: "User")
end
end
Instead of using "owner_id:", I want to use the "project_id" value from parameters column. So how can i do this?
Thank you very much in advanced! :)
The parameters field contains a simple yaml dump, so not really easy to search efficiently.
A simple solution would be to use LIKE operator, for instance
PublicActivity::Activity.where("parameters LIKE '%project_id: #{#project.id}%'")
You might want to consider to add custom fields instead.
Thanks for the answer, but I got a better solution than using the parameters value or custom field.
Here is how my activities_controller looks like right now:
class ActivitiesController < ApplicationController
def index
activity_table = PublicActivity::Activity.arel_table
# We want to view all activity of folders related to projects we are follwing
folder_ids = Folder.where(project_id: current_user.following_projects.pluck(:id)).pluck(:id)
# Generate query for all activity related to folders we care about
folders_query = activity_table[:trackable_type].eq('Folder').and(
activity_table[:trackable_id].in(folder_ids)
)
# Generate query for all users that we follow
users_query = activity_table[:owner_id].in(current_user.following_users.pluck(:id))
activity_query = folders_query.or(users_query)
#activities = PublicActivity::Activity.where(activity_query)
end
end
By using this way, I could easily combine the activities from the "Users" and also from the "Projects" that the user follows.
You can modify it to add any other activities such as from the "Comments" or "Voting".
Hope this will help other people out there that are using public_activity gem! :)
In a Rails 3.2 app, I have a validation for an attachment type.
Attachment model:
class Attachment < ActiveRecord::Base
validates_presence_of :name
validates_attachment_presence :attach, :message => "No file selected"
validate :check_type
def check_type
if self.costproject_id != nil
if self.attach_content_type != 'application/pdf'
self.errors.add(:pdf, " ONLY")
return false
end
end
end
But, the return false sends me to this URL:
http://localhost:3000/attachments
I want it to go back to the previous input screen:
http://localhost:3000/attachments/new?costproject_id=2
How do I accomplish that?
Thanks!!
UPDATE1
Perhaps the redirect has to take place in the controller?
format.html { render action: "new" }
Attachment controller:
# POST /attachments
# POST /attachments.json
def create
#attachment = Attachment.new(params[:attachment])
respond_to do |format|
if #attachment.save
format.html { redirect_to session.delete(:return_to), notice: 'Attachment was successfully created.' }
format.json { render json: #attachment, status: :created, location: #attachment }
else
format.html { render action: "new" }
format.json { render json: #attachment.errors, status: :unprocessable_entity }
end
end
end
I changed this line:
format.html { render action: "new" }
To:
format.html { redirect_to request.referer }
And now it goes back to where I want. But, I've lost the errors - they don't display.
To help you understand what's going on here. When you go to /attachments/new you are rendering a form. When you press submit, you are sending a POST request to /attachments, which invokes the create action.
You're create action appears to be solid and idomatic. However when you render action: "new" in the case of an error, it's not a full redirect, it's rendering the form in the context of the current action.
Normally this is fine, because idomatic rails would have you building a single, very similar, model object in both new and create, and the form for helper would render that object. However your new action is creating all kinds of objects based on a large assortment of query parameters, which I'm guessing is why you are seeing behavior you don't like.
I expect your final solution will involve bringing all those parameters into Attachment in some way, if they don't need to be saved to the database, you can make attr_accessors on Attachment
# Model
class Attachment < ActiveRecord::Base
attr_accessor :worequest_id, :workorder_id # etc
end
# View
<%= form_for #attachment do |f| %>
<%= f.hidden :worequest_id %>
<% end %>
Approaching it this way, your post request params will look like
{
attachment:
{
worequest_id: 1,
# etc
}
}
And you would also need to rework your query params to nest the inidividual ids inside of an attachment
/attachments/new?[attachment][worequest_id]=1
This way you could build attachment from params in both actions:
Attachment.new(params[:attachment])
And now your current create action should more or less work as expected, because now it's idomatic rails.
You still aren't going to get the new action with the same query params, but since you are taking those params and filling them in hidden fields on the form, they won't be lost when you try and fail to create. In any case, unless you do something to persist the values between requests, the POST to /attachments is going to wipe out the ery params.
Try this.
Replace
return false
With
redirect_to request.referrer || root_url
Note: root_url here is a catchall. Also this is Rails 4, I do not know if it also applies to Rails 3. Worth a try, though.
Debug ideas
First confirm a simple redirect_to root_url (or whatever name you use for your root) works in your controller
redirect_to root_url
Then, once redirect_to confirmed working, focus on getting the REST interface "request." information. There's a Rails 3 discussion here which may help you.
How to get request referer path?